blob: 6df4af6e99cc588bfe9fd6e38d731ce828946e33 [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
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan 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
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan 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
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100820 /* Time stamp */
821 __net_timestamp(skb);
822
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200823 hci_send_to_control(skb, skip_sk);
824 kfree_skb(skb);
825
826 return 0;
827}
828
829static int new_settings(struct hci_dev *hdev, struct sock *skip)
830{
831 __le32 ev;
832
833 ev = cpu_to_le32(get_current_settings(hdev));
834
835 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
836}
837
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300838static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200839{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300840 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200841 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200842 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200843 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200844 u8 scan;
845 int err;
846
Johan Hedberg03811012010-12-08 00:21:06 +0200847 BT_DBG("request for hci%u", index);
848
849 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200850 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200852
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100853 timeout = get_unaligned_le16(&cp->timeout);
854 if (!cp->val && timeout > 0)
855 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
856 MGMT_STATUS_INVALID_PARAMS);
857
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200858 hdev = hci_dev_get(index);
859 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200860 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
861 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300863 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200864
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200865 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200866 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
867 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200868 goto failed;
869 }
870
871 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
872 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200873 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
874 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200875 goto failed;
876 }
877
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200878 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
879 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
880 MGMT_STATUS_REJECTED);
881 goto failed;
882 }
883
884 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200885 bool changed = false;
886
887 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
888 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
889 changed = true;
890 }
891
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200892 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200893 if (err < 0)
894 goto failed;
895
896 if (changed)
897 err = new_settings(hdev, sk);
898
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200899 goto failed;
900 }
901
902 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200903 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200904 goto failed;
905 }
906
907 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
908 if (!cmd) {
909 err = -ENOMEM;
910 goto failed;
911 }
912
913 scan = SCAN_PAGE;
914
915 if (cp->val)
916 scan |= SCAN_INQUIRY;
917 else
918 cancel_delayed_work(&hdev->discov_off);
919
920 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
921 if (err < 0)
922 mgmt_pending_remove(cmd);
923
Johan Hedberg03811012010-12-08 00:21:06 +0200924 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200925 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200926
927failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300928 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200929 hci_dev_put(hdev);
930
931 return err;
932}
933
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300934static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200935{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300936 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200937 struct hci_dev *hdev;
938 struct pending_cmd *cmd;
939 u8 scan;
940 int err;
941
Johan Hedberge41d8b42010-12-13 21:07:03 +0200942 BT_DBG("request for hci%u", index);
943
Johan Hedberg03811012010-12-08 00:21:06 +0200944 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200945 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
946 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200947
948 hdev = hci_dev_get(index);
949 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200950 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
951 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200952
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300953 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200954
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200955 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200956 bool changed = false;
957
958 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
959 changed = true;
960
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200961 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200963 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200964 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
965 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
966 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200967
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200968 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200969 if (err < 0)
970 goto failed;
971
972 if (changed)
973 err = new_settings(hdev, sk);
974
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200975 goto failed;
976 }
977
978 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
979 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200980 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
981 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 goto failed;
983 }
984
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200985 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200986 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200987 goto failed;
988 }
989
990 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
991 if (!cmd) {
992 err = -ENOMEM;
993 goto failed;
994 }
995
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200996 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200997 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200998 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200999 scan = 0;
1000
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001001 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1002 hdev->discov_timeout > 0)
1003 cancel_delayed_work(&hdev->discov_off);
1004 }
1005
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1007 if (err < 0)
1008 mgmt_pending_remove(cmd);
1009
1010failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001011 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001012 hci_dev_put(hdev);
1013
1014 return err;
1015}
1016
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001017static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001018{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001019 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001020 struct hci_dev *hdev;
1021 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001022
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023 BT_DBG("request for hci%u", index);
1024
1025 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001026 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1027 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001028
1029 hdev = hci_dev_get(index);
1030 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001031 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1032 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001034 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001035
1036 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001037 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001038 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001039 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001041 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042 if (err < 0)
1043 goto failed;
1044
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001045 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046
1047failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001048 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001049 hci_dev_put(hdev);
1050
1051 return err;
1052}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001053
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001054static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1055{
1056 struct mgmt_mode *cp = data;
1057 struct pending_cmd *cmd;
1058 struct hci_dev *hdev;
1059 uint8_t val;
1060 int err;
1061
1062 BT_DBG("request for hci%u", index);
1063
1064 if (len != sizeof(*cp))
1065 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1066 MGMT_STATUS_INVALID_PARAMS);
1067
1068 hdev = hci_dev_get(index);
1069 if (!hdev)
1070 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1071 MGMT_STATUS_INVALID_PARAMS);
1072
1073 hci_dev_lock(hdev);
1074
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001075 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001076 bool changed = false;
1077
1078 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1079 &hdev->dev_flags)) {
1080 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1081 changed = true;
1082 }
1083
1084 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1085 if (err < 0)
1086 goto failed;
1087
1088 if (changed)
1089 err = new_settings(hdev, sk);
1090
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001091 goto failed;
1092 }
1093
1094 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1095 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1096 MGMT_STATUS_BUSY);
1097 goto failed;
1098 }
1099
1100 val = !!cp->val;
1101
1102 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1103 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1104 goto failed;
1105 }
1106
1107 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1108 if (!cmd) {
1109 err = -ENOMEM;
1110 goto failed;
1111 }
1112
1113 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1114 if (err < 0) {
1115 mgmt_pending_remove(cmd);
1116 goto failed;
1117 }
1118
1119failed:
1120 hci_dev_unlock(hdev);
1121 hci_dev_put(hdev);
1122
1123 return err;
1124}
1125
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001126static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1127{
1128 struct mgmt_mode *cp = data;
1129 struct pending_cmd *cmd;
1130 struct hci_dev *hdev;
1131 uint8_t val;
1132 int err;
1133
1134 BT_DBG("request for hci%u", index);
1135
1136 if (len != sizeof(*cp))
1137 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1138 MGMT_STATUS_INVALID_PARAMS);
1139
1140 hdev = hci_dev_get(index);
1141 if (!hdev)
1142 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1143 MGMT_STATUS_INVALID_PARAMS);
1144
1145 hci_dev_lock(hdev);
1146
Johan Hedberg6c8f12c2012-02-22 16:35:26 +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 Hedbergc0ecddc2012-02-22 12:38:31 +02001153 val = !!cp->val;
1154
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001155 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001156 bool changed = false;
1157
1158 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1159 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1160 changed = true;
1161 }
1162
1163 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1164 if (err < 0)
1165 goto failed;
1166
1167 if (changed)
1168 err = new_settings(hdev, sk);
1169
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001170 goto failed;
1171 }
1172
1173 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1174 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1175 goto failed;
1176 }
1177
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001178 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1179 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1180 goto failed;
1181 }
1182
1183 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1184 if (!cmd) {
1185 err = -ENOMEM;
1186 goto failed;
1187 }
1188
1189 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1190 if (err < 0) {
1191 mgmt_pending_remove(cmd);
1192 goto failed;
1193 }
1194
1195failed:
1196 hci_dev_unlock(hdev);
1197 hci_dev_put(hdev);
1198
1199 return err;
1200}
1201
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001202static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1203{
1204 struct mgmt_mode *cp = data;
1205 struct hci_dev *hdev;
1206 int err;
1207
1208 BT_DBG("request for hci%u", index);
1209
1210 if (len != sizeof(*cp))
1211 return cmd_status(sk, index, MGMT_OP_SET_HS,
1212 MGMT_STATUS_INVALID_PARAMS);
1213
1214 hdev = hci_dev_get(index);
1215 if (!hdev)
1216 return cmd_status(sk, index, MGMT_OP_SET_HS,
1217 MGMT_STATUS_INVALID_PARAMS);
1218
1219 if (!enable_hs) {
1220 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1221 MGMT_STATUS_NOT_SUPPORTED);
1222 goto failed;
1223 }
1224
1225 if (cp->val)
1226 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1227 else
1228 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1229
1230 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1231
1232failed:
1233 hci_dev_put(hdev);
1234 return err;
1235}
1236
Johan Hedberg06199cf2012-02-22 16:37:11 +02001237static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1238{
1239 struct mgmt_mode *cp = data;
1240 struct hci_cp_write_le_host_supported hci_cp;
1241 struct pending_cmd *cmd;
1242 struct hci_dev *hdev;
1243 int err;
1244 u8 val;
1245
1246 BT_DBG("request for hci%u", index);
1247
1248 if (len != sizeof(*cp))
1249 return cmd_status(sk, index, MGMT_OP_SET_LE,
1250 MGMT_STATUS_INVALID_PARAMS);
1251
1252 hdev = hci_dev_get(index);
1253 if (!hdev)
1254 return cmd_status(sk, index, MGMT_OP_SET_LE,
1255 MGMT_STATUS_INVALID_PARAMS);
1256
1257 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1258 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1259 MGMT_STATUS_NOT_SUPPORTED);
1260 goto failed;
1261 }
1262
1263 val = !!cp->val;
1264
1265 if (!hdev_is_powered(hdev)) {
1266 bool changed = false;
1267
1268 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1269 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1270 changed = true;
1271 }
1272
1273 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1274 if (err < 0)
1275 goto failed;
1276
1277 if (changed)
1278 err = new_settings(hdev, sk);
1279
1280 goto failed;
1281 }
1282
1283 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1284 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1285 goto failed;
1286 }
1287
1288 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1289 if (!cmd) {
1290 err = -ENOMEM;
1291 goto failed;
1292 }
1293
1294 memset(&hci_cp, 0, sizeof(hci_cp));
1295
1296 if (val) {
1297 hci_cp.le = val;
1298 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1299 }
1300
1301 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1302 sizeof(hci_cp), &hci_cp);
1303 if (err < 0) {
1304 mgmt_pending_remove(cmd);
1305 goto failed;
1306 }
1307
1308failed:
1309 hci_dev_put(hdev);
1310 return err;
1311}
1312
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001313static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001314{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001315 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001316 struct hci_dev *hdev;
1317 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001318 int err;
1319
Szymon Janc4e51eae2011-02-25 19:05:48 +01001320 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001321
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001322 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001323 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1324 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001325
Szymon Janc4e51eae2011-02-25 19:05:48 +01001326 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001327 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001328 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1329 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001331 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332
1333 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1334 if (!uuid) {
1335 err = -ENOMEM;
1336 goto failed;
1337 }
1338
1339 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001340 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341
1342 list_add(&uuid->list, &hdev->uuids);
1343
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001344 err = update_class(hdev);
1345 if (err < 0)
1346 goto failed;
1347
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001348 err = update_eir(hdev);
1349 if (err < 0)
1350 goto failed;
1351
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001352 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001353
1354failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001355 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001356 hci_dev_put(hdev);
1357
1358 return err;
1359}
1360
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001361static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001362{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001363 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001364 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001365 struct hci_dev *hdev;
1366 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 +02001367 int err, found;
1368
Szymon Janc4e51eae2011-02-25 19:05:48 +01001369 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001370
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001371 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001372 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1373 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001374
Szymon Janc4e51eae2011-02-25 19:05:48 +01001375 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001376 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001377 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1378 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001379
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001380 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001381
1382 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1383 err = hci_uuids_clear(hdev);
1384 goto unlock;
1385 }
1386
1387 found = 0;
1388
1389 list_for_each_safe(p, n, &hdev->uuids) {
1390 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1391
1392 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1393 continue;
1394
1395 list_del(&match->list);
1396 found++;
1397 }
1398
1399 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001400 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1401 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001402 goto unlock;
1403 }
1404
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001405 err = update_class(hdev);
1406 if (err < 0)
1407 goto unlock;
1408
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001409 err = update_eir(hdev);
1410 if (err < 0)
1411 goto unlock;
1412
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001413 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001414
1415unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001416 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001417 hci_dev_put(hdev);
1418
1419 return err;
1420}
1421
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001422static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001423{
1424 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001425 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001426 int err;
1427
Szymon Janc4e51eae2011-02-25 19:05:48 +01001428 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001429
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001430 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001431 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1432 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001433
Szymon Janc4e51eae2011-02-25 19:05:48 +01001434 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001435 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001436 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1437 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001438
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001439 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001440
Johan Hedbergb5235a62012-02-21 14:32:24 +02001441 if (!hdev_is_powered(hdev)) {
1442 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1443 MGMT_STATUS_NOT_POWERED);
1444 goto unlock;
1445 }
1446
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447 hdev->major_class = cp->major;
1448 hdev->minor_class = cp->minor;
1449
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001450 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001451 hci_dev_unlock(hdev);
1452 cancel_delayed_work_sync(&hdev->service_cache);
1453 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001454 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001455 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001456
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001457 err = update_class(hdev);
1458
1459 if (err == 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001460 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1461 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001462
Johan Hedbergb5235a62012-02-21 14:32:24 +02001463unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001464 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001465 hci_dev_put(hdev);
1466
1467 return err;
1468}
1469
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001470static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001471{
1472 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001473 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001474 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001475 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001476
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001477 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001478 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1479 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001480
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001481 key_count = get_unaligned_le16(&cp->key_count);
1482
Johan Hedberg86742e12011-11-07 23:13:38 +02001483 expected_len = sizeof(*cp) + key_count *
1484 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001485 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001486 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001487 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001488 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1489 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001490 }
1491
Szymon Janc4e51eae2011-02-25 19:05:48 +01001492 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001493 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001494 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1495 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001496
Szymon Janc4e51eae2011-02-25 19:05:48 +01001497 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001498 key_count);
1499
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001500 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501
1502 hci_link_keys_clear(hdev);
1503
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001504 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001505
1506 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001507 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001509 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001510
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001511 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001512 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001513
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001514 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1515 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001516 }
1517
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001518 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001519
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001520 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001521 hci_dev_put(hdev);
1522
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001523 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001524}
1525
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001526static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1527 u8 addr_type, struct sock *skip_sk)
1528{
1529 struct mgmt_ev_device_unpaired ev;
1530
1531 bacpy(&ev.addr.bdaddr, bdaddr);
1532 ev.addr.type = addr_type;
1533
1534 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1535 skip_sk);
1536}
1537
Johan Hedberg124f6e32012-02-09 13:50:12 +02001538static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001539{
1540 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001541 struct mgmt_cp_unpair_device *cp = data;
1542 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001543 struct hci_cp_disconnect dc;
1544 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001545 struct hci_conn *conn;
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001546 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001547 int err;
1548
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001549 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001550 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001551 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001552
Szymon Janc4e51eae2011-02-25 19:05:48 +01001553 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001554 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001555 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001556 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001557
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001558 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001559
Johan Hedberga8a1d192011-11-10 15:54:38 +02001560 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001561 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1562 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001563
Johan Hedberg124f6e32012-02-09 13:50:12 +02001564 if (cp->addr.type == MGMT_ADDR_BREDR)
1565 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1566 else
1567 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001568
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001569 if (err < 0) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001570 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001571 goto unlock;
1572 }
1573
Johan Hedberga8a1d192011-11-10 15:54:38 +02001574 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001575 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1576 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001577 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001578 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001579 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001580
Johan Hedberg124f6e32012-02-09 13:50:12 +02001581 if (cp->addr.type == MGMT_ADDR_BREDR)
1582 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1583 &cp->addr.bdaddr);
1584 else
1585 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1586 &cp->addr.bdaddr);
1587
Johan Hedberga8a1d192011-11-10 15:54:38 +02001588 if (!conn) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001589 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1590 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001591 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001592 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001593 }
1594
Johan Hedberg124f6e32012-02-09 13:50:12 +02001595 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1596 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001597 if (!cmd) {
1598 err = -ENOMEM;
1599 goto unlock;
1600 }
1601
1602 put_unaligned_le16(conn->handle, &dc.handle);
1603 dc.reason = 0x13; /* Remote User Terminated Connection */
1604 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1605 if (err < 0)
1606 mgmt_pending_remove(cmd);
1607
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001608unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001609 if (err < 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001610 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1611 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001612 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001613 hci_dev_put(hdev);
1614
1615 return err;
1616}
1617
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001618static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001619{
1620 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001621 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001622 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001623 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001624 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001625 int err;
1626
1627 BT_DBG("");
1628
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001629 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001630 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1631 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001632
Szymon Janc4e51eae2011-02-25 19:05:48 +01001633 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001634 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001635 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1636 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001638 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001639
1640 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001641 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1642 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001643 goto failed;
1644 }
1645
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001646 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001647 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1648 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001649 goto failed;
1650 }
1651
Johan Hedberg88c3df12012-02-09 14:27:38 +02001652 if (cp->addr.type == MGMT_ADDR_BREDR)
1653 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1654 else
1655 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001656
Johan Hedberg8962ee72011-01-20 12:40:27 +02001657 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001658 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1659 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001660 goto failed;
1661 }
1662
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001663 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001664 if (!cmd) {
1665 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001666 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001667 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001668
1669 put_unaligned_le16(conn->handle, &dc.handle);
1670 dc.reason = 0x13; /* Remote User Terminated Connection */
1671
1672 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1673 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001674 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001675
1676failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001677 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001678 hci_dev_put(hdev);
1679
1680 return err;
1681}
1682
Johan Hedberg48264f02011-11-09 13:58:58 +02001683static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001684{
1685 switch (link_type) {
1686 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001687 switch (addr_type) {
1688 case ADDR_LE_DEV_PUBLIC:
1689 return MGMT_ADDR_LE_PUBLIC;
1690 case ADDR_LE_DEV_RANDOM:
1691 return MGMT_ADDR_LE_RANDOM;
1692 default:
1693 return MGMT_ADDR_INVALID;
1694 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001695 case ACL_LINK:
1696 return MGMT_ADDR_BREDR;
1697 default:
1698 return MGMT_ADDR_INVALID;
1699 }
1700}
1701
Szymon Janc8ce62842011-03-01 16:55:32 +01001702static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001703{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001704 struct mgmt_rp_get_connections *rp;
1705 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001706 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001707 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001708 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001709 int i, err;
1710
1711 BT_DBG("");
1712
Szymon Janc4e51eae2011-02-25 19:05:48 +01001713 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001714 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001715 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1716 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001717
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001718 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001719
1720 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001721 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1722 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1723 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001724 }
1725
Johan Hedberg4c659c32011-11-07 23:13:39 +02001726 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001727 rp = kmalloc(rp_len, GFP_ATOMIC);
1728 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001729 err = -ENOMEM;
1730 goto unlock;
1731 }
1732
Johan Hedberg2784eb42011-01-21 13:56:35 +02001733 put_unaligned_le16(count, &rp->conn_count);
1734
Johan Hedberg2784eb42011-01-21 13:56:35 +02001735 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001736 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001737 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1738 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001739 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001740 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001741 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1742 continue;
1743 i++;
1744 }
1745
1746 /* Recalculate length in case of filtered SCO connections, etc */
1747 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001748
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001749 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001750
1751unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001752 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001753 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001754 hci_dev_put(hdev);
1755 return err;
1756}
1757
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001758static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1759 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1760{
1761 struct pending_cmd *cmd;
1762 int err;
1763
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001764 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001765 sizeof(*cp));
1766 if (!cmd)
1767 return -ENOMEM;
1768
Johan Hedbergd8457692012-02-17 14:24:57 +02001769 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1770 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001771 if (err < 0)
1772 mgmt_pending_remove(cmd);
1773
1774 return err;
1775}
1776
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001777static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778{
1779 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001780 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001781 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001782 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001783 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001784 int err;
1785
1786 BT_DBG("");
1787
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001788 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001789 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1790 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001791
Szymon Janc4e51eae2011-02-25 19:05:48 +01001792 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001793 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001794 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1795 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001797 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001799 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001800 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1801 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001802 goto failed;
1803 }
1804
Johan Hedbergd8457692012-02-17 14:24:57 +02001805 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001806 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001807 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1808 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001809 goto failed;
1810 }
1811
1812 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001813 struct mgmt_cp_pin_code_neg_reply ncp;
1814
1815 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001816
1817 BT_ERR("PIN code is not 16 bytes long");
1818
1819 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1820 if (err >= 0)
1821 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001822 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001823
1824 goto failed;
1825 }
1826
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001827 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1828 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001829 if (!cmd) {
1830 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001831 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001832 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001833
Johan Hedbergd8457692012-02-17 14:24:57 +02001834 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001835 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001836 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001837
1838 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1839 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001840 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001841
1842failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001843 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001844 hci_dev_put(hdev);
1845
1846 return err;
1847}
1848
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001849static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001850{
1851 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001852 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001853 int err;
1854
1855 BT_DBG("");
1856
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001857 if (len != sizeof(*cp))
1858 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001859 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001860
Szymon Janc4e51eae2011-02-25 19:05:48 +01001861 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001862 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001864 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001865
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001866 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001867
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001868 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001869 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001870 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001871 goto failed;
1872 }
1873
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001874 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001875
1876failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001877 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001878 hci_dev_put(hdev);
1879
1880 return err;
1881}
1882
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001883static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001884{
1885 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001886 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001887
1888 BT_DBG("");
1889
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001890 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001891 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1892 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001893
Szymon Janc4e51eae2011-02-25 19:05:48 +01001894 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001895 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001896 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1897 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001898
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001899 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001900
1901 hdev->io_capability = cp->io_capability;
1902
1903 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001904 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001905
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001906 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001907 hci_dev_put(hdev);
1908
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001909 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001910}
1911
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1913{
1914 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001915 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001916
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001917 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001918 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1919 continue;
1920
Johan Hedberge9a416b2011-02-19 12:05:56 -03001921 if (cmd->user_data != conn)
1922 continue;
1923
1924 return cmd;
1925 }
1926
1927 return NULL;
1928}
1929
1930static void pairing_complete(struct pending_cmd *cmd, u8 status)
1931{
1932 struct mgmt_rp_pair_device rp;
1933 struct hci_conn *conn = cmd->user_data;
1934
Johan Hedbergba4e5642011-11-11 00:07:34 +02001935 bacpy(&rp.addr.bdaddr, &conn->dst);
1936 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001938 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1939 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940
1941 /* So we don't get further callbacks for this connection */
1942 conn->connect_cfm_cb = NULL;
1943 conn->security_cfm_cb = NULL;
1944 conn->disconn_cfm_cb = NULL;
1945
1946 hci_conn_put(conn);
1947
Johan Hedberga664b5b2011-02-19 12:06:02 -03001948 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001949}
1950
1951static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1952{
1953 struct pending_cmd *cmd;
1954
1955 BT_DBG("status %u", status);
1956
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001957 cmd = find_pairing(conn);
1958 if (!cmd)
1959 BT_DBG("Unable to find a pending command");
1960 else
Johan Hedberge2113262012-02-18 15:20:03 +02001961 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001962}
1963
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001964static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001965{
1966 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001967 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001968 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001969 struct pending_cmd *cmd;
1970 u8 sec_level, auth_type;
1971 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001972 int err;
1973
1974 BT_DBG("");
1975
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001976 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001977 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1978 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001979
Szymon Janc4e51eae2011-02-25 19:05:48 +01001980 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001981 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001982 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1983 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001985 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001986
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001987 sec_level = BT_SECURITY_MEDIUM;
1988 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001989 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001990 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001991 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001992
Johan Hedbergba4e5642011-11-11 00:07:34 +02001993 if (cp->addr.type == MGMT_ADDR_BREDR)
1994 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001995 auth_type);
1996 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001997 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001998 auth_type);
1999
Johan Hedberg1425acb2011-11-11 00:07:35 +02002000 memset(&rp, 0, sizeof(rp));
2001 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2002 rp.addr.type = cp->addr.type;
2003
Ville Tervo30e76272011-02-22 16:10:53 -03002004 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002005 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2006 MGMT_STATUS_CONNECT_FAILED,
2007 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002008 goto unlock;
2009 }
2010
2011 if (conn->connect_cfm_cb) {
2012 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002013 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2014 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002015 goto unlock;
2016 }
2017
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002018 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002019 if (!cmd) {
2020 err = -ENOMEM;
2021 hci_conn_put(conn);
2022 goto unlock;
2023 }
2024
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002025 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002026 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002027 conn->connect_cfm_cb = pairing_complete_cb;
2028
Johan Hedberge9a416b2011-02-19 12:05:56 -03002029 conn->security_cfm_cb = pairing_complete_cb;
2030 conn->disconn_cfm_cb = pairing_complete_cb;
2031 conn->io_capability = cp->io_cap;
2032 cmd->user_data = conn;
2033
2034 if (conn->state == BT_CONNECTED &&
2035 hci_conn_security(conn, sec_level, auth_type))
2036 pairing_complete(cmd, 0);
2037
2038 err = 0;
2039
2040unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002041 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002042 hci_dev_put(hdev);
2043
2044 return err;
2045}
2046
Johan Hedberg28424702012-02-02 04:02:29 +02002047static int cancel_pair_device(struct sock *sk, u16 index,
2048 unsigned char *data, u16 len)
2049{
2050 struct mgmt_addr_info *addr = (void *) data;
2051 struct hci_dev *hdev;
2052 struct pending_cmd *cmd;
2053 struct hci_conn *conn;
2054 int err;
2055
2056 BT_DBG("");
2057
2058 if (len != sizeof(*addr))
2059 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2060 MGMT_STATUS_INVALID_PARAMS);
2061
2062 hdev = hci_dev_get(index);
2063 if (!hdev)
2064 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2065 MGMT_STATUS_INVALID_PARAMS);
2066
2067 hci_dev_lock(hdev);
2068
2069 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2070 if (!cmd) {
2071 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2072 MGMT_STATUS_INVALID_PARAMS);
2073 goto unlock;
2074 }
2075
2076 conn = cmd->user_data;
2077
2078 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2079 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2080 MGMT_STATUS_INVALID_PARAMS);
2081 goto unlock;
2082 }
2083
2084 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2085
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002086 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002087 sizeof(*addr));
2088unlock:
2089 hci_dev_unlock(hdev);
2090 hci_dev_put(hdev);
2091
2092 return err;
2093}
2094
Brian Gix0df4c182011-11-16 13:53:13 -08002095static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002096 u8 type, u16 mgmt_op, u16 hci_op,
2097 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002098{
Johan Hedberga5c29682011-02-19 12:05:57 -03002099 struct pending_cmd *cmd;
2100 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002101 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002102 int err;
2103
Szymon Janc4e51eae2011-02-25 19:05:48 +01002104 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002105 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002106 return cmd_status(sk, index, mgmt_op,
2107 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002108
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002109 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002110
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002111 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002112 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2113 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002114 }
2115
Johan Hedberg272d90d2012-02-09 15:26:12 +02002116 if (type == MGMT_ADDR_BREDR)
2117 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2118 else
Brian Gix47c15e22011-11-16 13:53:14 -08002119 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002120
Johan Hedberg272d90d2012-02-09 15:26:12 +02002121 if (!conn) {
2122 err = cmd_status(sk, index, mgmt_op,
2123 MGMT_STATUS_NOT_CONNECTED);
2124 goto done;
2125 }
2126
2127 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002128 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002129 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002130
Brian Gix5fe57d92011-12-21 16:12:13 -08002131 if (!err)
2132 err = cmd_status(sk, index, mgmt_op,
2133 MGMT_STATUS_SUCCESS);
2134 else
2135 err = cmd_status(sk, index, mgmt_op,
2136 MGMT_STATUS_FAILED);
2137
Brian Gix47c15e22011-11-16 13:53:14 -08002138 goto done;
2139 }
2140
Brian Gix0df4c182011-11-16 13:53:13 -08002141 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002142 if (!cmd) {
2143 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002144 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002145 }
2146
Brian Gix0df4c182011-11-16 13:53:13 -08002147 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002148 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2149 struct hci_cp_user_passkey_reply cp;
2150
2151 bacpy(&cp.bdaddr, bdaddr);
2152 cp.passkey = passkey;
2153 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2154 } else
2155 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2156
Johan Hedberga664b5b2011-02-19 12:06:02 -03002157 if (err < 0)
2158 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002159
Brian Gix0df4c182011-11-16 13:53:13 -08002160done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002161 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002162 hci_dev_put(hdev);
2163
2164 return err;
2165}
2166
Brian Gix0df4c182011-11-16 13:53:13 -08002167static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2168{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002169 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002170
2171 BT_DBG("");
2172
2173 if (len != sizeof(*cp))
2174 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2175 MGMT_STATUS_INVALID_PARAMS);
2176
Johan Hedberg272d90d2012-02-09 15:26:12 +02002177 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2178 MGMT_OP_USER_CONFIRM_REPLY,
2179 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002180}
2181
2182static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2183 u16 len)
2184{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002185 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002186
2187 BT_DBG("");
2188
2189 if (len != sizeof(*cp))
2190 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2191 MGMT_STATUS_INVALID_PARAMS);
2192
Johan Hedberg272d90d2012-02-09 15:26:12 +02002193 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2194 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2195 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002196}
2197
Brian Gix604086b2011-11-23 08:28:33 -08002198static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2199{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002200 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002201
2202 BT_DBG("");
2203
2204 if (len != sizeof(*cp))
2205 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2206 EINVAL);
2207
Johan Hedberg272d90d2012-02-09 15:26:12 +02002208 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2209 MGMT_OP_USER_PASSKEY_REPLY,
2210 HCI_OP_USER_PASSKEY_REPLY,
2211 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002212}
2213
2214static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2215 u16 len)
2216{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002217 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002218
2219 BT_DBG("");
2220
2221 if (len != sizeof(*cp))
2222 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2223 EINVAL);
2224
Johan Hedberg272d90d2012-02-09 15:26:12 +02002225 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2226 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2227 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002228}
2229
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002230static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002231 u16 len)
2232{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002233 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002234 struct hci_cp_write_local_name hci_cp;
2235 struct hci_dev *hdev;
2236 struct pending_cmd *cmd;
2237 int err;
2238
2239 BT_DBG("");
2240
2241 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002242 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2243 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002244
2245 hdev = hci_dev_get(index);
2246 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002247 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2248 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002249
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002250 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002251
Johan Hedbergb5235a62012-02-21 14:32:24 +02002252 if (!hdev_is_powered(hdev)) {
2253 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2254 MGMT_STATUS_NOT_POWERED);
2255 goto failed;
2256 }
2257
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002258 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2259 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002260 if (!cmd) {
2261 err = -ENOMEM;
2262 goto failed;
2263 }
2264
2265 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2266 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2267 &hci_cp);
2268 if (err < 0)
2269 mgmt_pending_remove(cmd);
2270
2271failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002272 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002273 hci_dev_put(hdev);
2274
2275 return err;
2276}
2277
Szymon Jancc35938b2011-03-22 13:12:21 +01002278static int read_local_oob_data(struct sock *sk, u16 index)
2279{
2280 struct hci_dev *hdev;
2281 struct pending_cmd *cmd;
2282 int err;
2283
2284 BT_DBG("hci%u", index);
2285
2286 hdev = hci_dev_get(index);
2287 if (!hdev)
2288 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002289 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002290
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002291 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002292
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002293 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002294 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002295 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002296 goto unlock;
2297 }
2298
2299 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2300 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002301 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002302 goto unlock;
2303 }
2304
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002305 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002306 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2307 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002308 goto unlock;
2309 }
2310
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002311 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002312 if (!cmd) {
2313 err = -ENOMEM;
2314 goto unlock;
2315 }
2316
2317 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2318 if (err < 0)
2319 mgmt_pending_remove(cmd);
2320
2321unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002322 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002323 hci_dev_put(hdev);
2324
2325 return err;
2326}
2327
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002328static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2329 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002330{
2331 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002332 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002333 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002334 int err;
2335
2336 BT_DBG("hci%u ", index);
2337
2338 if (len != sizeof(*cp))
2339 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002340 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002341
2342 hdev = hci_dev_get(index);
2343 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002344 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2345 MGMT_STATUS_INVALID_PARAMS,
2346 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002347
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002348 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002349
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002350 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002351 cp->randomizer);
2352 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002353 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002354 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002355 status = 0;
2356
2357 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2358 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002359
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002360 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002361 hci_dev_put(hdev);
2362
2363 return err;
2364}
2365
2366static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002367 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002368{
2369 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002370 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002371 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002372 int err;
2373
2374 BT_DBG("hci%u ", index);
2375
2376 if (len != sizeof(*cp))
2377 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002378 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002379
2380 hdev = hci_dev_get(index);
2381 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002382 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2383 MGMT_STATUS_INVALID_PARAMS,
2384 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002385
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002386 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002387
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002388 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002389 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002390 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002391 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002392 status = 0;
2393
2394 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2395 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002396
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002397 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002398 hci_dev_put(hdev);
2399
2400 return err;
2401}
2402
Andre Guedes5e0452c2012-02-17 20:39:38 -03002403static int discovery(struct hci_dev *hdev)
2404{
2405 int err;
2406
2407 if (lmp_host_le_capable(hdev)) {
2408 if (lmp_bredr_capable(hdev)) {
2409 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2410 LE_SCAN_INT, LE_SCAN_WIN,
2411 LE_SCAN_TIMEOUT_BREDR_LE);
2412 } else {
2413 hdev->discovery.type = DISCOV_TYPE_LE;
2414 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2415 LE_SCAN_INT, LE_SCAN_WIN,
2416 LE_SCAN_TIMEOUT_LE_ONLY);
2417 }
2418 } else {
2419 hdev->discovery.type = DISCOV_TYPE_BREDR;
2420 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2421 }
2422
2423 return err;
2424}
2425
2426int mgmt_interleaved_discovery(struct hci_dev *hdev)
2427{
2428 int err;
2429
2430 BT_DBG("%s", hdev->name);
2431
2432 hci_dev_lock(hdev);
2433
2434 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2435 if (err < 0)
2436 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2437
2438 hci_dev_unlock(hdev);
2439
2440 return err;
2441}
2442
Johan Hedberg450dfda2011-11-12 11:58:22 +02002443static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002444 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002445{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002446 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002447 struct pending_cmd *cmd;
2448 struct hci_dev *hdev;
2449 int err;
2450
2451 BT_DBG("hci%u", index);
2452
Johan Hedberg450dfda2011-11-12 11:58:22 +02002453 if (len != sizeof(*cp))
2454 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2455 MGMT_STATUS_INVALID_PARAMS);
2456
Johan Hedberg14a53662011-04-27 10:29:56 -04002457 hdev = hci_dev_get(index);
2458 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002459 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2460 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002461
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002462 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002463
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002464 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002465 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2466 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002467 goto failed;
2468 }
2469
Johan Hedbergff9ef572012-01-04 14:23:45 +02002470 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2471 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2472 MGMT_STATUS_BUSY);
2473 goto failed;
2474 }
2475
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002476 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002477 if (!cmd) {
2478 err = -ENOMEM;
2479 goto failed;
2480 }
2481
Andre Guedes4aab14e2012-02-17 20:39:36 -03002482 hdev->discovery.type = cp->type;
2483
2484 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002485 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002486 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002487 break;
2488
2489 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002490 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2491 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002492 break;
2493
Andre Guedes5e0452c2012-02-17 20:39:38 -03002494 case DISCOV_TYPE_INTERLEAVED:
2495 err = discovery(hdev);
2496 break;
2497
Andre Guedesf39799f2012-02-17 20:39:35 -03002498 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002499 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002500 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002501
Johan Hedberg14a53662011-04-27 10:29:56 -04002502 if (err < 0)
2503 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002504 else
2505 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002506
2507failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002508 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002509 hci_dev_put(hdev);
2510
2511 return err;
2512}
2513
Johan Hedbergd9306502012-02-20 23:25:18 +02002514static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002515{
Johan Hedbergd9306502012-02-20 23:25:18 +02002516 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002517 struct hci_dev *hdev;
2518 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002519 struct hci_cp_remote_name_req_cancel cp;
2520 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002521 int err;
2522
2523 BT_DBG("hci%u", index);
2524
Johan Hedbergd9306502012-02-20 23:25:18 +02002525 if (len != sizeof(*mgmt_cp))
2526 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2527 MGMT_STATUS_INVALID_PARAMS);
2528
Johan Hedberg14a53662011-04-27 10:29:56 -04002529 hdev = hci_dev_get(index);
2530 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002531 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2532 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002533
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002534 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002535
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002536 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002537 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2538 MGMT_STATUS_REJECTED,
2539 &mgmt_cp->type, sizeof(mgmt_cp->type));
2540 goto unlock;
2541 }
2542
2543 if (hdev->discovery.type != mgmt_cp->type) {
2544 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2545 MGMT_STATUS_INVALID_PARAMS,
2546 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002547 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002548 }
2549
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002550 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002551 if (!cmd) {
2552 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002553 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002554 }
2555
Andre Guedes343f9352012-02-17 20:39:37 -03002556 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002557 err = hci_cancel_inquiry(hdev);
2558 if (err < 0)
2559 mgmt_pending_remove(cmd);
2560 else
2561 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2562 goto unlock;
2563 }
2564
2565 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2566 if (!e) {
2567 mgmt_pending_remove(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002568 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002569 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002570 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2571 goto unlock;
2572 }
2573
2574 bacpy(&cp.bdaddr, &e->data.bdaddr);
2575 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2576 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002577 if (err < 0)
2578 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002579 else
2580 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002581
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002582unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002583 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002584 hci_dev_put(hdev);
2585
2586 return err;
2587}
2588
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002589static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002590{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002591 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002592 struct inquiry_entry *e;
2593 struct hci_dev *hdev;
2594 int err;
2595
2596 BT_DBG("hci%u", index);
2597
2598 if (len != sizeof(*cp))
2599 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2600 MGMT_STATUS_INVALID_PARAMS);
2601
2602 hdev = hci_dev_get(index);
2603 if (!hdev)
2604 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2605 MGMT_STATUS_INVALID_PARAMS);
2606
2607 hci_dev_lock(hdev);
2608
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002609 if (!hci_discovery_active(hdev)) {
2610 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2611 MGMT_STATUS_FAILED);
2612 goto failed;
2613 }
2614
Johan Hedberga198e7b2012-02-17 14:27:06 +02002615 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002616 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002617 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002618 MGMT_STATUS_INVALID_PARAMS);
2619 goto failed;
2620 }
2621
2622 if (cp->name_known) {
2623 e->name_state = NAME_KNOWN;
2624 list_del(&e->list);
2625 } else {
2626 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002627 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002628 }
2629
2630 err = 0;
2631
2632failed:
2633 hci_dev_unlock(hdev);
2634
2635 return err;
2636}
2637
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002638static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002639{
2640 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002641 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002642 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002643 int err;
2644
2645 BT_DBG("hci%u", index);
2646
Antti Julku7fbec222011-06-15 12:01:15 +03002647 if (len != sizeof(*cp))
2648 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002649 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002650
2651 hdev = hci_dev_get(index);
2652 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002653 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2654 MGMT_STATUS_INVALID_PARAMS,
2655 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002656
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002657 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002658
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002659 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002660 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002661 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002662 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002663 status = 0;
2664
2665 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2666 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002667
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002668 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002669 hci_dev_put(hdev);
2670
2671 return err;
2672}
2673
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002674static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002675{
2676 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002677 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002678 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002679 int err;
2680
2681 BT_DBG("hci%u", index);
2682
Antti Julku7fbec222011-06-15 12:01:15 +03002683 if (len != sizeof(*cp))
2684 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002685 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002686
2687 hdev = hci_dev_get(index);
2688 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002689 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2690 MGMT_STATUS_INVALID_PARAMS,
2691 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002692
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002693 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002694
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002695 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002696 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002697 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002698 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002699 status = 0;
2700
2701 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2702 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002703
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002704 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002705 hci_dev_put(hdev);
2706
2707 return err;
2708}
2709
Antti Julkuf6422ec2011-06-22 13:11:56 +03002710static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002711 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002712{
2713 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002714 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002715 struct hci_cp_write_page_scan_activity acp;
2716 u8 type;
2717 int err;
2718
2719 BT_DBG("hci%u", index);
2720
2721 if (len != sizeof(*cp))
2722 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002723 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002724
2725 hdev = hci_dev_get(index);
2726 if (!hdev)
2727 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002728 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002729 if (!hdev_is_powered(hdev))
2730 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2731 MGMT_STATUS_NOT_POWERED);
2732
2733 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2734 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2735 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002736
2737 hci_dev_lock(hdev);
2738
Johan Hedbergf7c68692011-12-15 00:47:36 +02002739 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002740 type = PAGE_SCAN_TYPE_INTERLACED;
2741 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2742 } else {
2743 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2744 acp.interval = 0x0800; /* default 1.28 sec page scan */
2745 }
2746
2747 acp.window = 0x0012; /* default 11.25 msec page scan window */
2748
2749 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2750 sizeof(acp), &acp);
2751 if (err < 0) {
2752 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002753 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002754 goto done;
2755 }
2756
2757 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2758 if (err < 0) {
2759 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002760 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002761 goto done;
2762 }
2763
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002764 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2765 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002766done:
2767 hci_dev_unlock(hdev);
2768 hci_dev_put(hdev);
2769
2770 return err;
2771}
2772
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002773static int load_long_term_keys(struct sock *sk, u16 index,
2774 void *cp_data, u16 len)
2775{
2776 struct hci_dev *hdev;
2777 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2778 u16 key_count, expected_len;
2779 int i;
2780
2781 if (len < sizeof(*cp))
2782 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2783 EINVAL);
2784
2785 key_count = get_unaligned_le16(&cp->key_count);
2786
2787 expected_len = sizeof(*cp) + key_count *
2788 sizeof(struct mgmt_ltk_info);
2789 if (expected_len != len) {
2790 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2791 len, expected_len);
2792 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2793 EINVAL);
2794 }
2795
2796 hdev = hci_dev_get(index);
2797 if (!hdev)
2798 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2799 ENODEV);
2800
2801 BT_DBG("hci%u key_count %u", index, key_count);
2802
2803 hci_dev_lock(hdev);
2804
2805 hci_smp_ltks_clear(hdev);
2806
2807 for (i = 0; i < key_count; i++) {
2808 struct mgmt_ltk_info *key = &cp->keys[i];
2809 u8 type;
2810
2811 if (key->master)
2812 type = HCI_SMP_LTK;
2813 else
2814 type = HCI_SMP_LTK_SLAVE;
2815
2816 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2817 type, 0, key->authenticated, key->val,
2818 key->enc_size, key->ediv, key->rand);
2819 }
2820
2821 hci_dev_unlock(hdev);
2822 hci_dev_put(hdev);
2823
2824 return 0;
2825}
2826
Johan Hedberg03811012010-12-08 00:21:06 +02002827int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2828{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002829 void *buf;
2830 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002831 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002832 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002833 int err;
2834
2835 BT_DBG("got %zu bytes", msglen);
2836
2837 if (msglen < sizeof(*hdr))
2838 return -EINVAL;
2839
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002840 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002841 if (!buf)
2842 return -ENOMEM;
2843
2844 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2845 err = -EFAULT;
2846 goto done;
2847 }
2848
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002849 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002850 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002851 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002852 len = get_unaligned_le16(&hdr->len);
2853
2854 if (len != msglen - sizeof(*hdr)) {
2855 err = -EINVAL;
2856 goto done;
2857 }
2858
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002859 cp = buf + sizeof(*hdr);
2860
Johan Hedberg03811012010-12-08 00:21:06 +02002861 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002862 case MGMT_OP_READ_VERSION:
2863 err = read_version(sk);
2864 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002865 case MGMT_OP_READ_COMMANDS:
2866 err = read_commands(sk);
2867 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002868 case MGMT_OP_READ_INDEX_LIST:
2869 err = read_index_list(sk);
2870 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002871 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002872 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002873 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002874 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002875 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002876 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002877 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002878 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002879 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002880 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002881 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002882 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002883 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002884 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002885 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002886 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002887 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002888 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002889 case MGMT_OP_SET_LINK_SECURITY:
2890 err = set_link_security(sk, index, cp, len);
2891 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002892 case MGMT_OP_SET_SSP:
2893 err = set_ssp(sk, index, cp, len);
2894 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002895 case MGMT_OP_SET_HS:
2896 err = set_hs(sk, index, cp, len);
2897 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002898 case MGMT_OP_SET_LE:
2899 err = set_le(sk, index, cp, len);
2900 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002901 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002902 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002903 break;
2904 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002905 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002906 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002907 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002908 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002909 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002910 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002911 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002912 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002913 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002914 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002915 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002916 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002917 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002918 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002919 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002920 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002921 break;
2922 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002923 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002924 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002925 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002926 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002927 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002928 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002929 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002930 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002931 case MGMT_OP_CANCEL_PAIR_DEVICE:
2932 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2933 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002934 case MGMT_OP_UNPAIR_DEVICE:
2935 err = unpair_device(sk, index, cp, len);
2936 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002937 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002938 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002939 break;
2940 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002941 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002942 break;
Brian Gix604086b2011-11-23 08:28:33 -08002943 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002944 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002945 break;
2946 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002947 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002948 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002949 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002950 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002951 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002952 case MGMT_OP_READ_LOCAL_OOB_DATA:
2953 err = read_local_oob_data(sk, index);
2954 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002955 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002956 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002957 break;
2958 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002959 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002960 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002961 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002962 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002963 break;
2964 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002965 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002966 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002967 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002969 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002970 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002971 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002972 break;
2973 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002974 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002975 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002976 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2977 err = load_long_term_keys(sk, index, cp, len);
2978 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002979 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002980 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002981 err = cmd_status(sk, index, opcode,
2982 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002983 break;
2984 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002985
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002986 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002987 goto done;
2988
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002989 err = msglen;
2990
2991done:
2992 kfree(buf);
2993 return err;
2994}
2995
Johan Hedbergb24752f2011-11-03 14:40:33 +02002996static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2997{
2998 u8 *status = data;
2999
3000 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3001 mgmt_pending_remove(cmd);
3002}
3003
Johan Hedberg744cf192011-11-08 20:40:14 +02003004int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003005{
Johan Hedberg744cf192011-11-08 20:40:14 +02003006 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003007}
3008
Johan Hedberg744cf192011-11-08 20:40:14 +02003009int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003010{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003011 u8 status = ENODEV;
3012
Johan Hedberg744cf192011-11-08 20:40:14 +02003013 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003014
Johan Hedberg744cf192011-11-08 20:40:14 +02003015 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003016}
3017
3018struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003019 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003020 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003021};
3022
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003023static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003024{
Johan Hedberg03811012010-12-08 00:21:06 +02003025 struct cmd_lookup *match = data;
3026
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003027 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003028
3029 list_del(&cmd->list);
3030
3031 if (match->sk == NULL) {
3032 match->sk = cmd->sk;
3033 sock_hold(match->sk);
3034 }
3035
3036 mgmt_pending_free(cmd);
3037}
3038
Johan Hedberg744cf192011-11-08 20:40:14 +02003039int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003040{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003041 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003042 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003043
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003044 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3045 return 0;
3046
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003047 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003048
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003049 if (powered) {
3050 u8 scan = 0;
3051
3052 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3053 scan |= SCAN_PAGE;
3054 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3055 scan |= SCAN_INQUIRY;
3056
3057 if (scan)
3058 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3059 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003060 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003061 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003062 }
3063
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003064 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003065
3066 if (match.sk)
3067 sock_put(match.sk);
3068
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003069 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003070}
3071
Johan Hedberg744cf192011-11-08 20:40:14 +02003072int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003073{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003074 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003075 bool changed = false;
3076 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003077
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003078 if (discoverable) {
3079 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3080 changed = true;
3081 } else {
3082 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3083 changed = true;
3084 }
Johan Hedberg03811012010-12-08 00:21:06 +02003085
Johan Hedberged9b5f22012-02-21 20:47:06 +02003086 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3087 &match);
3088
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003089 if (changed)
3090 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003091
Johan Hedberg03811012010-12-08 00:21:06 +02003092 if (match.sk)
3093 sock_put(match.sk);
3094
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003095 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003096}
3097
Johan Hedberg744cf192011-11-08 20:40:14 +02003098int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003099{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003100 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003101 bool changed = false;
3102 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003103
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003104 if (connectable) {
3105 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3106 changed = true;
3107 } else {
3108 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3109 changed = true;
3110 }
Johan Hedberg03811012010-12-08 00:21:06 +02003111
Johan Hedberged9b5f22012-02-21 20:47:06 +02003112 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3113 &match);
3114
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003115 if (changed)
3116 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003117
3118 if (match.sk)
3119 sock_put(match.sk);
3120
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003121 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003122}
3123
Johan Hedberg744cf192011-11-08 20:40:14 +02003124int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003125{
Johan Hedbergca69b792011-11-11 18:10:00 +02003126 u8 mgmt_err = mgmt_status(status);
3127
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003128 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003129 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003130 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003131
3132 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003133 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003134 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003135
3136 return 0;
3137}
3138
Johan Hedberg744cf192011-11-08 20:40:14 +02003139int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3140 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003141{
Johan Hedberg86742e12011-11-07 23:13:38 +02003142 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003143
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003144 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003145
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003146 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003147 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3148 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003149 ev.key.type = key->type;
3150 memcpy(ev.key.val, key->val, 16);
3151 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003152
Johan Hedberg744cf192011-11-08 20:40:14 +02003153 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003154}
Johan Hedbergf7520542011-01-20 12:34:39 +02003155
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003156int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3157{
3158 struct mgmt_ev_new_long_term_key ev;
3159
3160 memset(&ev, 0, sizeof(ev));
3161
3162 ev.store_hint = persistent;
3163 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3164 ev.key.addr.type = key->bdaddr_type;
3165 ev.key.authenticated = key->authenticated;
3166 ev.key.enc_size = key->enc_size;
3167 ev.key.ediv = key->ediv;
3168
3169 if (key->type == HCI_SMP_LTK)
3170 ev.key.master = 1;
3171
3172 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3173 memcpy(ev.key.val, key->val, sizeof(key->val));
3174
3175 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3176 &ev, sizeof(ev), NULL);
3177}
3178
Johan Hedbergafc747a2012-01-15 18:11:07 +02003179int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003180 u8 addr_type, u8 *name, u8 name_len,
3181 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003182{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003183 char buf[512];
3184 struct mgmt_ev_device_connected *ev = (void *) buf;
3185 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003186
Johan Hedbergb644ba32012-01-17 21:48:47 +02003187 bacpy(&ev->addr.bdaddr, bdaddr);
3188 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003189
Johan Hedbergb644ba32012-01-17 21:48:47 +02003190 if (name_len > 0)
3191 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3192 name, name_len);
3193
3194 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3195 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3196 EIR_CLASS_OF_DEV, dev_class, 3);
3197
3198 put_unaligned_le16(eir_len, &ev->eir_len);
3199
3200 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3201 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003202}
3203
Johan Hedberg8962ee72011-01-20 12:40:27 +02003204static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3205{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003206 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003207 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003208 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003209
Johan Hedberg88c3df12012-02-09 14:27:38 +02003210 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3211 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003212
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003213 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3214 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003215
3216 *sk = cmd->sk;
3217 sock_hold(*sk);
3218
Johan Hedberga664b5b2011-02-19 12:06:02 -03003219 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003220}
3221
Johan Hedberg124f6e32012-02-09 13:50:12 +02003222static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003223{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003224 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003225 struct mgmt_cp_unpair_device *cp = cmd->param;
3226 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003227
3228 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003229 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3230 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003231
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003232 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3233
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003234 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003235
3236 mgmt_pending_remove(cmd);
3237}
3238
Johan Hedbergafc747a2012-01-15 18:11:07 +02003239int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3240 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003241{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003242 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003243 struct sock *sk = NULL;
3244 int err;
3245
Johan Hedberg744cf192011-11-08 20:40:14 +02003246 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003247
Johan Hedbergf7520542011-01-20 12:34:39 +02003248 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003249 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003250
Johan Hedbergafc747a2012-01-15 18:11:07 +02003251 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3252 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003253
3254 if (sk)
3255 sock_put(sk);
3256
Johan Hedberg124f6e32012-02-09 13:50:12 +02003257 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003258 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003259
Johan Hedberg8962ee72011-01-20 12:40:27 +02003260 return err;
3261}
3262
Johan Hedberg88c3df12012-02-09 14:27:38 +02003263int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3264 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003265{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003266 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003267 struct pending_cmd *cmd;
3268 int err;
3269
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003270 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003271 if (!cmd)
3272 return -ENOENT;
3273
Johan Hedberg88c3df12012-02-09 14:27:38 +02003274 bacpy(&rp.addr.bdaddr, bdaddr);
3275 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003276
Johan Hedberg88c3df12012-02-09 14:27:38 +02003277 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003278 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003279
Johan Hedberga664b5b2011-02-19 12:06:02 -03003280 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003281
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003282 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3283 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003284 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003285}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003286
Johan Hedberg48264f02011-11-09 13:58:58 +02003287int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3288 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003289{
3290 struct mgmt_ev_connect_failed ev;
3291
Johan Hedberg4c659c32011-11-07 23:13:39 +02003292 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003293 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003294 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003295
Johan Hedberg744cf192011-11-08 20:40:14 +02003296 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003297}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003298
Johan Hedberg744cf192011-11-08 20:40:14 +02003299int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003300{
3301 struct mgmt_ev_pin_code_request ev;
3302
Johan Hedbergd8457692012-02-17 14:24:57 +02003303 bacpy(&ev.addr.bdaddr, bdaddr);
3304 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003305 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003306
Johan Hedberg744cf192011-11-08 20:40:14 +02003307 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003308 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003309}
3310
Johan Hedberg744cf192011-11-08 20:40:14 +02003311int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3312 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003313{
3314 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003315 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003316 int err;
3317
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003318 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003319 if (!cmd)
3320 return -ENOENT;
3321
Johan Hedbergd8457692012-02-17 14:24:57 +02003322 bacpy(&rp.addr.bdaddr, bdaddr);
3323 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003324
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003325 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3326 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003327
Johan Hedberga664b5b2011-02-19 12:06:02 -03003328 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003329
3330 return err;
3331}
3332
Johan Hedberg744cf192011-11-08 20:40:14 +02003333int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3334 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003335{
3336 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003337 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003338 int err;
3339
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003340 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003341 if (!cmd)
3342 return -ENOENT;
3343
Johan Hedbergd8457692012-02-17 14:24:57 +02003344 bacpy(&rp.addr.bdaddr, bdaddr);
3345 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003346
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003347 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3348 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003349
Johan Hedberga664b5b2011-02-19 12:06:02 -03003350 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003351
3352 return err;
3353}
Johan Hedberga5c29682011-02-19 12:05:57 -03003354
Johan Hedberg744cf192011-11-08 20:40:14 +02003355int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003356 u8 link_type, u8 addr_type, __le32 value,
3357 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003358{
3359 struct mgmt_ev_user_confirm_request ev;
3360
Johan Hedberg744cf192011-11-08 20:40:14 +02003361 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003362
Johan Hedberg272d90d2012-02-09 15:26:12 +02003363 bacpy(&ev.addr.bdaddr, bdaddr);
3364 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003365 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003366 put_unaligned_le32(value, &ev.value);
3367
Johan Hedberg744cf192011-11-08 20:40:14 +02003368 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003369 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003370}
3371
Johan Hedberg272d90d2012-02-09 15:26:12 +02003372int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3373 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003374{
3375 struct mgmt_ev_user_passkey_request ev;
3376
3377 BT_DBG("%s", hdev->name);
3378
Johan Hedberg272d90d2012-02-09 15:26:12 +02003379 bacpy(&ev.addr.bdaddr, bdaddr);
3380 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003381
3382 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3383 NULL);
3384}
3385
Brian Gix0df4c182011-11-16 13:53:13 -08003386static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003387 u8 link_type, u8 addr_type, u8 status,
3388 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003389{
3390 struct pending_cmd *cmd;
3391 struct mgmt_rp_user_confirm_reply rp;
3392 int err;
3393
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003394 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003395 if (!cmd)
3396 return -ENOENT;
3397
Johan Hedberg272d90d2012-02-09 15:26:12 +02003398 bacpy(&rp.addr.bdaddr, bdaddr);
3399 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003400 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3401 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003402
Johan Hedberga664b5b2011-02-19 12:06:02 -03003403 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003404
3405 return err;
3406}
3407
Johan Hedberg744cf192011-11-08 20:40:14 +02003408int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003409 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003410{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003411 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3412 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003413}
3414
Johan Hedberg272d90d2012-02-09 15:26:12 +02003415int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3416 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003417{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003418 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3419 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003420}
Johan Hedberg2a611692011-02-19 12:06:00 -03003421
Brian Gix604086b2011-11-23 08:28:33 -08003422int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003423 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003424{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003425 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3426 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003427}
3428
Johan Hedberg272d90d2012-02-09 15:26:12 +02003429int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3430 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003431{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003432 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3433 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003434}
3435
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003436int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3437 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003438{
3439 struct mgmt_ev_auth_failed ev;
3440
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003441 bacpy(&ev.addr.bdaddr, bdaddr);
3442 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003443 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003444
Johan Hedberg744cf192011-11-08 20:40:14 +02003445 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003446}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003447
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003448int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3449{
3450 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003451 bool changed = false;
3452 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003453
3454 if (status) {
3455 u8 mgmt_err = mgmt_status(status);
3456 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3457 cmd_status_rsp, &mgmt_err);
3458 return 0;
3459 }
3460
Johan Hedberg47990ea2012-02-22 11:58:37 +02003461 if (test_bit(HCI_AUTH, &hdev->flags)) {
3462 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3463 changed = true;
3464 } else {
3465 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3466 changed = true;
3467 }
3468
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003469 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3470 &match);
3471
Johan Hedberg47990ea2012-02-22 11:58:37 +02003472 if (changed)
3473 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003474
3475 if (match.sk)
3476 sock_put(match.sk);
3477
3478 return err;
3479}
3480
Johan Hedbergcacaf522012-02-21 00:52:42 +02003481static int clear_eir(struct hci_dev *hdev)
3482{
3483 struct hci_cp_write_eir cp;
3484
3485 if (!(hdev->features[6] & LMP_EXT_INQ))
3486 return 0;
3487
Johan Hedbergc80da272012-02-22 15:38:48 +02003488 memset(hdev->eir, 0, sizeof(hdev->eir));
3489
Johan Hedbergcacaf522012-02-21 00:52:42 +02003490 memset(&cp, 0, sizeof(cp));
3491
3492 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3493}
3494
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003495int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003496{
3497 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003498 bool changed = false;
3499 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003500
3501 if (status) {
3502 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003503
3504 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3505 &hdev->dev_flags))
3506 err = new_settings(hdev, NULL);
3507
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003508 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3509 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003510
3511 return err;
3512 }
3513
3514 if (enable) {
3515 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3516 changed = true;
3517 } else {
3518 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3519 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003520 }
3521
3522 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3523
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003524 if (changed)
3525 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003526
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003527 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003528 sock_put(match.sk);
3529
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003530 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3531 update_eir(hdev);
3532 else
3533 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003534
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003535 return err;
3536}
3537
Johan Hedberg744cf192011-11-08 20:40:14 +02003538int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003539{
3540 struct pending_cmd *cmd;
3541 struct mgmt_cp_set_local_name ev;
3542 int err;
3543
3544 memset(&ev, 0, sizeof(ev));
3545 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3546
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003547 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003548 if (!cmd)
3549 goto send_event;
3550
3551 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003552 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003553 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003554 goto failed;
3555 }
3556
Johan Hedberg744cf192011-11-08 20:40:14 +02003557 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003558
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003559 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003560 sizeof(ev));
3561 if (err < 0)
3562 goto failed;
3563
3564send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003565 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003566 cmd ? cmd->sk : NULL);
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003567 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003568
3569failed:
3570 if (cmd)
3571 mgmt_pending_remove(cmd);
3572 return err;
3573}
Szymon Jancc35938b2011-03-22 13:12:21 +01003574
Johan Hedberg744cf192011-11-08 20:40:14 +02003575int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3576 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003577{
3578 struct pending_cmd *cmd;
3579 int err;
3580
Johan Hedberg744cf192011-11-08 20:40:14 +02003581 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003582
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003583 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003584 if (!cmd)
3585 return -ENOENT;
3586
3587 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003588 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003589 MGMT_OP_READ_LOCAL_OOB_DATA,
3590 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003591 } else {
3592 struct mgmt_rp_read_local_oob_data rp;
3593
3594 memcpy(rp.hash, hash, sizeof(rp.hash));
3595 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3596
Johan Hedberg744cf192011-11-08 20:40:14 +02003597 err = cmd_complete(cmd->sk, hdev->id,
3598 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003599 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003600 }
3601
3602 mgmt_pending_remove(cmd);
3603
3604 return err;
3605}
Johan Hedberge17acd42011-03-30 23:57:16 +03003606
Johan Hedberg06199cf2012-02-22 16:37:11 +02003607int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3608{
3609 struct cmd_lookup match = { NULL, hdev };
3610 bool changed = false;
3611 int err = 0;
3612
3613 if (status) {
3614 u8 mgmt_err = mgmt_status(status);
3615
3616 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3617 &hdev->dev_flags))
3618 err = new_settings(hdev, NULL);
3619
3620 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3621 cmd_status_rsp, &mgmt_err);
3622
3623 return err;
3624 }
3625
3626 if (enable) {
3627 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3628 changed = true;
3629 } else {
3630 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3631 changed = true;
3632 }
3633
3634 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3635
3636 if (changed)
3637 err = new_settings(hdev, match.sk);
3638
3639 if (match.sk)
3640 sock_put(match.sk);
3641
3642 return err;
3643}
3644
Johan Hedberg48264f02011-11-09 13:58:58 +02003645int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003646 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003647 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003648{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003649 char buf[512];
3650 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003651 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003652
Johan Hedberg1dc06092012-01-15 21:01:23 +02003653 /* Leave 5 bytes for a potential CoD field */
3654 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003655 return -EINVAL;
3656
Johan Hedberg1dc06092012-01-15 21:01:23 +02003657 memset(buf, 0, sizeof(buf));
3658
Johan Hedberge319d2e2012-01-15 19:51:59 +02003659 bacpy(&ev->addr.bdaddr, bdaddr);
3660 ev->addr.type = link_to_mgmt(link_type, addr_type);
3661 ev->rssi = rssi;
3662 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003663
Johan Hedberg1dc06092012-01-15 21:01:23 +02003664 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003665 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003666
Johan Hedberg1dc06092012-01-15 21:01:23 +02003667 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3668 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3669 dev_class, 3);
3670
3671 put_unaligned_le16(eir_len, &ev->eir_len);
3672
3673 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003674
Johan Hedberge319d2e2012-01-15 19:51:59 +02003675 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003676}
Johan Hedberga88a9652011-03-30 13:18:12 +03003677
Johan Hedbergb644ba32012-01-17 21:48:47 +02003678int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3679 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003680{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003681 struct mgmt_ev_device_found *ev;
3682 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3683 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003684
Johan Hedbergb644ba32012-01-17 21:48:47 +02003685 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003686
Johan Hedbergb644ba32012-01-17 21:48:47 +02003687 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003688
Johan Hedbergb644ba32012-01-17 21:48:47 +02003689 bacpy(&ev->addr.bdaddr, bdaddr);
3690 ev->addr.type = link_to_mgmt(link_type, addr_type);
3691 ev->rssi = rssi;
3692
3693 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3694 name_len);
3695
3696 put_unaligned_le16(eir_len, &ev->eir_len);
3697
Johan Hedberg053c7e02012-02-04 00:06:00 +02003698 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3699 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003700}
Johan Hedberg314b2382011-04-27 10:29:57 -04003701
Andre Guedes7a135102011-11-09 17:14:25 -03003702int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003703{
3704 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003705 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003706 int err;
3707
Andre Guedes203159d2012-02-13 15:41:01 -03003708 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3709
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003710 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003711 if (!cmd)
3712 return -ENOENT;
3713
Johan Hedbergf808e162012-02-19 12:52:07 +02003714 type = hdev->discovery.type;
3715
3716 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3717 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003718 mgmt_pending_remove(cmd);
3719
3720 return err;
3721}
3722
Andre Guedese6d465c2011-11-09 17:14:26 -03003723int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3724{
3725 struct pending_cmd *cmd;
3726 int err;
3727
3728 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3729 if (!cmd)
3730 return -ENOENT;
3731
Johan Hedbergd9306502012-02-20 23:25:18 +02003732 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3733 &hdev->discovery.type,
3734 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003735 mgmt_pending_remove(cmd);
3736
3737 return err;
3738}
Johan Hedberg314b2382011-04-27 10:29:57 -04003739
Johan Hedberg744cf192011-11-08 20:40:14 +02003740int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003741{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003742 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003743 struct pending_cmd *cmd;
3744
Andre Guedes343fb142011-11-22 17:14:19 -03003745 BT_DBG("%s discovering %u", hdev->name, discovering);
3746
Johan Hedberg164a6e72011-11-01 17:06:44 +02003747 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003748 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003749 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003750 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003751
3752 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003753 u8 type = hdev->discovery.type;
3754
Johan Hedbergd9306502012-02-20 23:25:18 +02003755 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003756 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003757 mgmt_pending_remove(cmd);
3758 }
3759
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003760 memset(&ev, 0, sizeof(ev));
3761 ev.type = hdev->discovery.type;
3762 ev.discovering = discovering;
3763
3764 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003765}
Antti Julku5e762442011-08-25 16:48:02 +03003766
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003767int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003768{
3769 struct pending_cmd *cmd;
3770 struct mgmt_ev_device_blocked ev;
3771
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003772 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003773
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003774 bacpy(&ev.addr.bdaddr, bdaddr);
3775 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003776
Johan Hedberg744cf192011-11-08 20:40:14 +02003777 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3778 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003779}
3780
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003781int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003782{
3783 struct pending_cmd *cmd;
3784 struct mgmt_ev_device_unblocked ev;
3785
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003786 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003787
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003788 bacpy(&ev.addr.bdaddr, bdaddr);
3789 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003790
Johan Hedberg744cf192011-11-08 20:40:14 +02003791 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3792 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003793}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003794
3795module_param(enable_hs, bool, 0644);
3796MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3797
3798module_param(enable_le, bool, 0644);
3799MODULE_PARM_DESC(enable_le, "Enable Low Energy support");