blob: 6850a8b46c62d99883eb34b7b1f619d1342318b6 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200538 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 return 0;
540
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200541 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
544 memset(&cp, 0, sizeof(cp));
545
546 create_eir(hdev, cp.data);
547
548 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
549 return 0;
550
551 memcpy(hdev->eir, cp.data, sizeof(cp.data));
552
553 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
554}
555
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200556static u8 get_service_classes(struct hci_dev *hdev)
557{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300558 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559 u8 val = 0;
560
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200563
564 return val;
565}
566
567static int update_class(struct hci_dev *hdev)
568{
569 u8 cod[3];
570
571 BT_DBG("%s", hdev->name);
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 return 0;
575
576 cod[0] = hdev->minor_class;
577 cod[1] = hdev->major_class;
578 cod[2] = get_service_classes(hdev);
579
580 if (memcmp(cod, hdev->dev_class, 3) == 0)
581 return 0;
582
583 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
584}
585
Johan Hedberg7d785252011-12-15 00:47:39 +0200586static void service_cache_off(struct work_struct *work)
587{
588 struct hci_dev *hdev = container_of(work, struct hci_dev,
589 service_cache.work);
590
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200591 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200592 return;
593
594 hci_dev_lock(hdev);
595
596 update_eir(hdev);
597 update_class(hdev);
598
599 hci_dev_unlock(hdev);
600}
601
602static void mgmt_init_hdev(struct hci_dev *hdev)
603{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200604 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200605 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
606
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200607 /* Non-mgmt controlled devices get this bit set
608 * implicitly so that pairing works for them, however
609 * for mgmt we require user-space to explicitly enable
610 * it
611 */
612 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
613 }
614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 schedule_delayed_work(&hdev->service_cache,
617 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
618}
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620static int read_controller_info(struct sock *sk, u16 index)
621{
622 struct mgmt_rp_read_info rp;
623 struct hci_dev *hdev;
624
625 BT_DBG("sock %p hci%u", sk, index);
626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_READ_INFO,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
635 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
637 memset(&rp, 0, sizeof(rp));
638
Johan Hedberg03811012010-12-08 00:21:06 +0200639 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200640
641 rp.version = hdev->hci_ver;
642
Johan Hedberg03811012010-12-08 00:21:06 +0200643 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644
645 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
646 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
647
648 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200649
650 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200651 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200652
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300653 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200654 hci_dev_put(hdev);
655
Johan Hedbergaee9b212012-02-18 15:07:59 +0200656 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200657}
658
659static void mgmt_pending_free(struct pending_cmd *cmd)
660{
661 sock_put(cmd->sk);
662 kfree(cmd->param);
663 kfree(cmd);
664}
665
666static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
667 struct hci_dev *hdev,
668 void *data, u16 len)
669{
670 struct pending_cmd *cmd;
671
672 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
673 if (!cmd)
674 return NULL;
675
676 cmd->opcode = opcode;
677 cmd->index = hdev->id;
678
679 cmd->param = kmalloc(len, GFP_ATOMIC);
680 if (!cmd->param) {
681 kfree(cmd);
682 return NULL;
683 }
684
685 if (data)
686 memcpy(cmd->param, data, len);
687
688 cmd->sk = sk;
689 sock_hold(sk);
690
691 list_add(&cmd->list, &hdev->mgmt_pending);
692
693 return cmd;
694}
695
696static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
697 void (*cb)(struct pending_cmd *cmd, void *data),
698 void *data)
699{
700 struct list_head *p, *n;
701
702 list_for_each_safe(p, n, &hdev->mgmt_pending) {
703 struct pending_cmd *cmd;
704
705 cmd = list_entry(p, struct pending_cmd, list);
706
707 if (opcode > 0 && cmd->opcode != opcode)
708 continue;
709
710 cb(cmd, data);
711 }
712}
713
714static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
715{
716 struct pending_cmd *cmd;
717
718 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
719 if (cmd->opcode == opcode)
720 return cmd;
721 }
722
723 return NULL;
724}
725
726static void mgmt_pending_remove(struct pending_cmd *cmd)
727{
728 list_del(&cmd->list);
729 mgmt_pending_free(cmd);
730}
731
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200732static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200733{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200734 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200735
Johan Hedbergaee9b212012-02-18 15:07:59 +0200736 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
737 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200738}
739
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300740static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200741{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300742 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200743 struct hci_dev *hdev;
744 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200745 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200746
Johan Hedberg03811012010-12-08 00:21:06 +0200747 BT_DBG("request for hci%u", index);
748
749 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200750 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
751 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200752
753 hdev = hci_dev_get(index);
754 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200755 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
756 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200757
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300758 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200759
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100760 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
761 cancel_delayed_work(&hdev->power_off);
762
763 if (cp->val) {
764 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
765 mgmt_powered(hdev, 1);
766 goto failed;
767 }
768 }
769
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200770 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200771 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200772 goto failed;
773 }
774
775 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200776 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
777 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200778 goto failed;
779 }
780
781 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
782 if (!cmd) {
783 err = -ENOMEM;
784 goto failed;
785 }
786
787 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200788 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200789 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200790 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200791
792 err = 0;
793
794failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300795 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200796 hci_dev_put(hdev);
797 return err;
798}
799
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200800static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
801 u16 data_len, struct sock *skip_sk)
802{
803 struct sk_buff *skb;
804 struct mgmt_hdr *hdr;
805
806 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
807 if (!skb)
808 return -ENOMEM;
809
810 hdr = (void *) skb_put(skb, sizeof(*hdr));
811 hdr->opcode = cpu_to_le16(event);
812 if (hdev)
813 hdr->index = cpu_to_le16(hdev->id);
814 else
815 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
816 hdr->len = cpu_to_le16(data_len);
817
818 if (data)
819 memcpy(skb_put(skb, data_len), data, data_len);
820
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100821 /* Time stamp */
822 __net_timestamp(skb);
823
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200824 hci_send_to_control(skb, skip_sk);
825 kfree_skb(skb);
826
827 return 0;
828}
829
830static int new_settings(struct hci_dev *hdev, struct sock *skip)
831{
832 __le32 ev;
833
834 ev = cpu_to_le32(get_current_settings(hdev));
835
836 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
837}
838
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300839static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200840{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300841 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200842 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200843 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200844 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200845 u8 scan;
846 int err;
847
Johan Hedberg03811012010-12-08 00:21:06 +0200848 BT_DBG("request for hci%u", index);
849
850 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200851 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
852 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200853
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100854 timeout = get_unaligned_le16(&cp->timeout);
855 if (!cp->val && timeout > 0)
856 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
857 MGMT_STATUS_INVALID_PARAMS);
858
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200859 hdev = hci_dev_get(index);
860 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200861 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
862 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200863
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300864 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200865
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200866 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200867 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
868 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200869 goto failed;
870 }
871
872 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
873 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200874 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
875 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200876 goto failed;
877 }
878
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200879 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
880 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
881 MGMT_STATUS_REJECTED);
882 goto failed;
883 }
884
885 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200886 bool changed = false;
887
888 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
889 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
890 changed = true;
891 }
892
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200893 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200894 if (err < 0)
895 goto failed;
896
897 if (changed)
898 err = new_settings(hdev, sk);
899
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200900 goto failed;
901 }
902
903 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100904 if (hdev->discov_timeout > 0) {
905 cancel_delayed_work(&hdev->discov_off);
906 hdev->discov_timeout = 0;
907 }
908
909 if (cp->val && timeout > 0) {
910 hdev->discov_timeout = timeout;
911 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
912 msecs_to_jiffies(hdev->discov_timeout * 1000));
913 }
914
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200915 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200916 goto failed;
917 }
918
919 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
920 if (!cmd) {
921 err = -ENOMEM;
922 goto failed;
923 }
924
925 scan = SCAN_PAGE;
926
927 if (cp->val)
928 scan |= SCAN_INQUIRY;
929 else
930 cancel_delayed_work(&hdev->discov_off);
931
932 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
933 if (err < 0)
934 mgmt_pending_remove(cmd);
935
Johan Hedberg03811012010-12-08 00:21:06 +0200936 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200937 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200938
939failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300940 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200941 hci_dev_put(hdev);
942
943 return err;
944}
945
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300946static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200947{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300948 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200949 struct hci_dev *hdev;
950 struct pending_cmd *cmd;
951 u8 scan;
952 int err;
953
Johan Hedberge41d8b42010-12-13 21:07:03 +0200954 BT_DBG("request for hci%u", index);
955
Johan Hedberg03811012010-12-08 00:21:06 +0200956 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200957 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
958 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
960 hdev = hci_dev_get(index);
961 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200962 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
963 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200964
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300965 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200967 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200968 bool changed = false;
969
970 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
971 changed = true;
972
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200973 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200974 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200975 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200976 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
977 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
978 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200979
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200980 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200981 if (err < 0)
982 goto failed;
983
984 if (changed)
985 err = new_settings(hdev, sk);
986
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200987 goto failed;
988 }
989
990 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
991 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200992 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
993 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 goto failed;
995 }
996
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200997 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200998 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200999 goto failed;
1000 }
1001
1002 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1003 if (!cmd) {
1004 err = -ENOMEM;
1005 goto failed;
1006 }
1007
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001008 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001010 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011 scan = 0;
1012
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001013 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1014 hdev->discov_timeout > 0)
1015 cancel_delayed_work(&hdev->discov_off);
1016 }
1017
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001018 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1019 if (err < 0)
1020 mgmt_pending_remove(cmd);
1021
1022failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001023 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001024 hci_dev_put(hdev);
1025
1026 return err;
1027}
1028
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001029static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001030{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001031 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001032 struct hci_dev *hdev;
1033 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001035 BT_DBG("request for hci%u", index);
1036
1037 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001038 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1039 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
1041 hdev = hci_dev_get(index);
1042 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001043 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1044 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001045
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001046 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047
1048 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001049 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001050 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001051 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001053 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054 if (err < 0)
1055 goto failed;
1056
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001057 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001058
1059failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001060 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001061 hci_dev_put(hdev);
1062
1063 return err;
1064}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001065
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001066static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1067{
1068 struct mgmt_mode *cp = data;
1069 struct pending_cmd *cmd;
1070 struct hci_dev *hdev;
1071 uint8_t val;
1072 int err;
1073
1074 BT_DBG("request for hci%u", index);
1075
1076 if (len != sizeof(*cp))
1077 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1078 MGMT_STATUS_INVALID_PARAMS);
1079
1080 hdev = hci_dev_get(index);
1081 if (!hdev)
1082 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1083 MGMT_STATUS_INVALID_PARAMS);
1084
1085 hci_dev_lock(hdev);
1086
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001087 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001088 bool changed = false;
1089
1090 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1091 &hdev->dev_flags)) {
1092 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1093 changed = true;
1094 }
1095
1096 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1097 if (err < 0)
1098 goto failed;
1099
1100 if (changed)
1101 err = new_settings(hdev, sk);
1102
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001103 goto failed;
1104 }
1105
1106 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1107 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1108 MGMT_STATUS_BUSY);
1109 goto failed;
1110 }
1111
1112 val = !!cp->val;
1113
1114 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1115 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1116 goto failed;
1117 }
1118
1119 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1120 if (!cmd) {
1121 err = -ENOMEM;
1122 goto failed;
1123 }
1124
1125 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1126 if (err < 0) {
1127 mgmt_pending_remove(cmd);
1128 goto failed;
1129 }
1130
1131failed:
1132 hci_dev_unlock(hdev);
1133 hci_dev_put(hdev);
1134
1135 return err;
1136}
1137
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001138static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1139{
1140 struct mgmt_mode *cp = data;
1141 struct pending_cmd *cmd;
1142 struct hci_dev *hdev;
1143 uint8_t val;
1144 int err;
1145
1146 BT_DBG("request for hci%u", index);
1147
1148 if (len != sizeof(*cp))
1149 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1150 MGMT_STATUS_INVALID_PARAMS);
1151
1152 hdev = hci_dev_get(index);
1153 if (!hdev)
1154 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1155 MGMT_STATUS_INVALID_PARAMS);
1156
1157 hci_dev_lock(hdev);
1158
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001159 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1160 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1161 MGMT_STATUS_NOT_SUPPORTED);
1162 goto failed;
1163 }
1164
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001165 val = !!cp->val;
1166
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001167 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001168 bool changed = false;
1169
1170 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1171 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1172 changed = true;
1173 }
1174
1175 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1176 if (err < 0)
1177 goto failed;
1178
1179 if (changed)
1180 err = new_settings(hdev, sk);
1181
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001182 goto failed;
1183 }
1184
1185 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1186 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1187 goto failed;
1188 }
1189
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001190 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1191 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1192 goto failed;
1193 }
1194
1195 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1196 if (!cmd) {
1197 err = -ENOMEM;
1198 goto failed;
1199 }
1200
1201 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1202 if (err < 0) {
1203 mgmt_pending_remove(cmd);
1204 goto failed;
1205 }
1206
1207failed:
1208 hci_dev_unlock(hdev);
1209 hci_dev_put(hdev);
1210
1211 return err;
1212}
1213
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001214static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1215{
1216 struct mgmt_mode *cp = data;
1217 struct hci_dev *hdev;
1218 int err;
1219
1220 BT_DBG("request for hci%u", index);
1221
1222 if (len != sizeof(*cp))
1223 return cmd_status(sk, index, MGMT_OP_SET_HS,
1224 MGMT_STATUS_INVALID_PARAMS);
1225
1226 hdev = hci_dev_get(index);
1227 if (!hdev)
1228 return cmd_status(sk, index, MGMT_OP_SET_HS,
1229 MGMT_STATUS_INVALID_PARAMS);
1230
1231 if (!enable_hs) {
1232 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1233 MGMT_STATUS_NOT_SUPPORTED);
1234 goto failed;
1235 }
1236
1237 if (cp->val)
1238 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1239 else
1240 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1241
1242 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1243
1244failed:
1245 hci_dev_put(hdev);
1246 return err;
1247}
1248
Johan Hedberg06199cf2012-02-22 16:37:11 +02001249static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1250{
1251 struct mgmt_mode *cp = data;
1252 struct hci_cp_write_le_host_supported hci_cp;
1253 struct pending_cmd *cmd;
1254 struct hci_dev *hdev;
1255 int err;
1256 u8 val;
1257
1258 BT_DBG("request for hci%u", index);
1259
1260 if (len != sizeof(*cp))
1261 return cmd_status(sk, index, MGMT_OP_SET_LE,
1262 MGMT_STATUS_INVALID_PARAMS);
1263
1264 hdev = hci_dev_get(index);
1265 if (!hdev)
1266 return cmd_status(sk, index, MGMT_OP_SET_LE,
1267 MGMT_STATUS_INVALID_PARAMS);
1268
1269 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1270 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1271 MGMT_STATUS_NOT_SUPPORTED);
1272 goto failed;
1273 }
1274
1275 val = !!cp->val;
1276
1277 if (!hdev_is_powered(hdev)) {
1278 bool changed = false;
1279
1280 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1281 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1282 changed = true;
1283 }
1284
1285 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1286 if (err < 0)
1287 goto failed;
1288
1289 if (changed)
1290 err = new_settings(hdev, sk);
1291
1292 goto failed;
1293 }
1294
1295 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1296 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1297 goto failed;
1298 }
1299
1300 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1301 if (!cmd) {
1302 err = -ENOMEM;
1303 goto failed;
1304 }
1305
1306 memset(&hci_cp, 0, sizeof(hci_cp));
1307
1308 if (val) {
1309 hci_cp.le = val;
1310 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1311 }
1312
1313 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1314 sizeof(hci_cp), &hci_cp);
1315 if (err < 0) {
1316 mgmt_pending_remove(cmd);
1317 goto failed;
1318 }
1319
1320failed:
1321 hci_dev_put(hdev);
1322 return err;
1323}
1324
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001325static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001326{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001327 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328 struct hci_dev *hdev;
1329 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330 int err;
1331
Szymon Janc4e51eae2011-02-25 19:05:48 +01001332 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001333
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001334 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001335 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1336 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001337
Szymon Janc4e51eae2011-02-25 19:05:48 +01001338 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001339 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001340 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1341 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001342
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001343 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001344
1345 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1346 if (!uuid) {
1347 err = -ENOMEM;
1348 goto failed;
1349 }
1350
1351 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001352 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001353
1354 list_add(&uuid->list, &hdev->uuids);
1355
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001356 err = update_class(hdev);
1357 if (err < 0)
1358 goto failed;
1359
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001360 err = update_eir(hdev);
1361 if (err < 0)
1362 goto failed;
1363
Johan Hedbergaee9b212012-02-18 15:07:59 +02001364 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001365
1366failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001367 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001368 hci_dev_put(hdev);
1369
1370 return err;
1371}
1372
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001373static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001374{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001375 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001376 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001377 struct hci_dev *hdev;
1378 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 +02001379 int err, found;
1380
Szymon Janc4e51eae2011-02-25 19:05:48 +01001381 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001382
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001383 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001384 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1385 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001386
Szymon Janc4e51eae2011-02-25 19:05:48 +01001387 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001388 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001389 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1390 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001391
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001392 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001393
1394 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1395 err = hci_uuids_clear(hdev);
1396 goto unlock;
1397 }
1398
1399 found = 0;
1400
1401 list_for_each_safe(p, n, &hdev->uuids) {
1402 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1403
1404 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1405 continue;
1406
1407 list_del(&match->list);
1408 found++;
1409 }
1410
1411 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001412 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1413 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001414 goto unlock;
1415 }
1416
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001417 err = update_class(hdev);
1418 if (err < 0)
1419 goto unlock;
1420
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001421 err = update_eir(hdev);
1422 if (err < 0)
1423 goto unlock;
1424
Johan Hedbergaee9b212012-02-18 15:07:59 +02001425 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001426
1427unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001428 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001429 hci_dev_put(hdev);
1430
1431 return err;
1432}
1433
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001434static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001435{
1436 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001437 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001438 int err;
1439
Szymon Janc4e51eae2011-02-25 19:05:48 +01001440 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001441
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001442 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001443 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1444 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001445
Szymon Janc4e51eae2011-02-25 19:05:48 +01001446 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001448 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1449 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001450
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001451 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001452
Johan Hedbergb5235a62012-02-21 14:32:24 +02001453 if (!hdev_is_powered(hdev)) {
1454 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1455 MGMT_STATUS_NOT_POWERED);
1456 goto unlock;
1457 }
1458
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001459 hdev->major_class = cp->major;
1460 hdev->minor_class = cp->minor;
1461
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001462 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001463 hci_dev_unlock(hdev);
1464 cancel_delayed_work_sync(&hdev->service_cache);
1465 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001466 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001467 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001468
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001469 err = update_class(hdev);
1470
1471 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001472 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1473 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001474
Johan Hedbergb5235a62012-02-21 14:32:24 +02001475unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001477 hci_dev_put(hdev);
1478
1479 return err;
1480}
1481
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001482static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001483{
1484 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001485 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001486 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001487 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001488
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001489 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001490 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1491 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001492
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001493 key_count = get_unaligned_le16(&cp->key_count);
1494
Johan Hedberg86742e12011-11-07 23:13:38 +02001495 expected_len = sizeof(*cp) + key_count *
1496 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001497 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001498 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001499 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001500 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1501 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001502 }
1503
Szymon Janc4e51eae2011-02-25 19:05:48 +01001504 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001505 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001506 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1507 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508
Szymon Janc4e51eae2011-02-25 19:05:48 +01001509 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001510 key_count);
1511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001512 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001513
1514 hci_link_keys_clear(hdev);
1515
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001516 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001517
1518 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001519 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001520 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001521 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001522
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001523 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001524 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001525
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001526 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1527 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001528 }
1529
Johan Hedbergaee9b212012-02-18 15:07:59 +02001530 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001531
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001532 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001533 hci_dev_put(hdev);
1534
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001535 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001536}
1537
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001538static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1539 u8 addr_type, struct sock *skip_sk)
1540{
1541 struct mgmt_ev_device_unpaired ev;
1542
1543 bacpy(&ev.addr.bdaddr, bdaddr);
1544 ev.addr.type = addr_type;
1545
1546 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1547 skip_sk);
1548}
1549
Johan Hedberg124f6e32012-02-09 13:50:12 +02001550static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001551{
1552 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001553 struct mgmt_cp_unpair_device *cp = data;
1554 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001555 struct hci_cp_disconnect dc;
1556 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001557 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001558 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001559 int err;
1560
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001561 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001562 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001563 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001564
Szymon Janc4e51eae2011-02-25 19:05:48 +01001565 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001566 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001567 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001568 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001569
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001570 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001571
Johan Hedberga8a1d192011-11-10 15:54:38 +02001572 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001573 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1574 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001575
Johan Hedberg124f6e32012-02-09 13:50:12 +02001576 if (cp->addr.type == MGMT_ADDR_BREDR)
1577 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1578 else
1579 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001580
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001581 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001582 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001583 goto unlock;
1584 }
1585
Johan Hedberga8a1d192011-11-10 15:54:38 +02001586 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001587 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1588 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001589 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001590 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001591 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001592
Johan Hedberg124f6e32012-02-09 13:50:12 +02001593 if (cp->addr.type == MGMT_ADDR_BREDR)
1594 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1595 &cp->addr.bdaddr);
1596 else
1597 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1598 &cp->addr.bdaddr);
1599
Johan Hedberga8a1d192011-11-10 15:54:38 +02001600 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001601 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1602 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001603 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001604 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001605 }
1606
Johan Hedberg124f6e32012-02-09 13:50:12 +02001607 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1608 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001609 if (!cmd) {
1610 err = -ENOMEM;
1611 goto unlock;
1612 }
1613
1614 put_unaligned_le16(conn->handle, &dc.handle);
1615 dc.reason = 0x13; /* Remote User Terminated Connection */
1616 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1617 if (err < 0)
1618 mgmt_pending_remove(cmd);
1619
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001620unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001621 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001622 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1623 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001624 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001625 hci_dev_put(hdev);
1626
1627 return err;
1628}
1629
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001630static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001631{
1632 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001633 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001634 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001635 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001636 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001637 int err;
1638
1639 BT_DBG("");
1640
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001641 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001642 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1643 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001644
Szymon Janc4e51eae2011-02-25 19:05:48 +01001645 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001646 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001647 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1648 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001649
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001650 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001651
1652 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001653 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1654 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001655 goto failed;
1656 }
1657
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001658 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001659 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1660 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001661 goto failed;
1662 }
1663
Johan Hedberg88c3df12012-02-09 14:27:38 +02001664 if (cp->addr.type == MGMT_ADDR_BREDR)
1665 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1666 else
1667 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001668
Johan Hedberg8962ee72011-01-20 12:40:27 +02001669 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001670 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1671 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001672 goto failed;
1673 }
1674
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001675 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001676 if (!cmd) {
1677 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001678 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001679 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001680
1681 put_unaligned_le16(conn->handle, &dc.handle);
1682 dc.reason = 0x13; /* Remote User Terminated Connection */
1683
1684 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1685 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001686 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001687
1688failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001689 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001690 hci_dev_put(hdev);
1691
1692 return err;
1693}
1694
Johan Hedberg48264f02011-11-09 13:58:58 +02001695static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001696{
1697 switch (link_type) {
1698 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001699 switch (addr_type) {
1700 case ADDR_LE_DEV_PUBLIC:
1701 return MGMT_ADDR_LE_PUBLIC;
1702 case ADDR_LE_DEV_RANDOM:
1703 return MGMT_ADDR_LE_RANDOM;
1704 default:
1705 return MGMT_ADDR_INVALID;
1706 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001707 case ACL_LINK:
1708 return MGMT_ADDR_BREDR;
1709 default:
1710 return MGMT_ADDR_INVALID;
1711 }
1712}
1713
Szymon Janc8ce62842011-03-01 16:55:32 +01001714static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001715{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001716 struct mgmt_rp_get_connections *rp;
1717 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001718 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001719 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001720 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001721 int i, err;
1722
1723 BT_DBG("");
1724
Szymon Janc4e51eae2011-02-25 19:05:48 +01001725 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001726 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001727 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1728 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001729
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001730 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001731
1732 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001733 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1734 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1735 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001736 }
1737
Johan Hedberg4c659c32011-11-07 23:13:39 +02001738 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001739 rp = kmalloc(rp_len, GFP_ATOMIC);
1740 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001741 err = -ENOMEM;
1742 goto unlock;
1743 }
1744
Johan Hedberg2784eb42011-01-21 13:56:35 +02001745 put_unaligned_le16(count, &rp->conn_count);
1746
Johan Hedberg2784eb42011-01-21 13:56:35 +02001747 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001748 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001749 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1750 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001751 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001752 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001753 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1754 continue;
1755 i++;
1756 }
1757
1758 /* Recalculate length in case of filtered SCO connections, etc */
1759 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001760
Johan Hedbergaee9b212012-02-18 15:07:59 +02001761 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001762
1763unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001764 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001765 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001766 hci_dev_put(hdev);
1767 return err;
1768}
1769
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001770static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1771 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1772{
1773 struct pending_cmd *cmd;
1774 int err;
1775
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001776 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001777 sizeof(*cp));
1778 if (!cmd)
1779 return -ENOMEM;
1780
Johan Hedbergd8457692012-02-17 14:24:57 +02001781 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1782 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001783 if (err < 0)
1784 mgmt_pending_remove(cmd);
1785
1786 return err;
1787}
1788
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001789static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001790{
1791 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001792 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001793 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001794 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001795 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796 int err;
1797
1798 BT_DBG("");
1799
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001800 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001801 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1802 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001803
Szymon Janc4e51eae2011-02-25 19:05:48 +01001804 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001805 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001806 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1807 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001808
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001809 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001810
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001811 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001812 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1813 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001814 goto failed;
1815 }
1816
Johan Hedbergd8457692012-02-17 14:24:57 +02001817 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001818 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001819 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1820 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001821 goto failed;
1822 }
1823
1824 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001825 struct mgmt_cp_pin_code_neg_reply ncp;
1826
1827 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001828
1829 BT_ERR("PIN code is not 16 bytes long");
1830
1831 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1832 if (err >= 0)
1833 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001834 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001835
1836 goto failed;
1837 }
1838
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001839 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1840 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001841 if (!cmd) {
1842 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001843 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001844 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001845
Johan Hedbergd8457692012-02-17 14:24:57 +02001846 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001847 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001848 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001849
1850 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1851 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001852 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001853
1854failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001856 hci_dev_put(hdev);
1857
1858 return err;
1859}
1860
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001861static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001862{
1863 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001864 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001865 int err;
1866
1867 BT_DBG("");
1868
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001869 if (len != sizeof(*cp))
1870 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001871 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001872
Szymon Janc4e51eae2011-02-25 19:05:48 +01001873 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001874 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001875 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001876 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001877
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001878 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001879
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001880 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001881 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001882 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001883 goto failed;
1884 }
1885
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001886 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001887
1888failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001889 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001890 hci_dev_put(hdev);
1891
1892 return err;
1893}
1894
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001895static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001896{
1897 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001898 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001899
1900 BT_DBG("");
1901
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001902 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001903 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1904 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001905
Szymon Janc4e51eae2011-02-25 19:05:48 +01001906 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001907 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001908 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1909 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001910
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001911 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001912
1913 hdev->io_capability = cp->io_capability;
1914
1915 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001916 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001917
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001918 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001919 hci_dev_put(hdev);
1920
Johan Hedbergaee9b212012-02-18 15:07:59 +02001921 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001922}
1923
Johan Hedberge9a416b2011-02-19 12:05:56 -03001924static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1925{
1926 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001927 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001928
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001929 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001930 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1931 continue;
1932
Johan Hedberge9a416b2011-02-19 12:05:56 -03001933 if (cmd->user_data != conn)
1934 continue;
1935
1936 return cmd;
1937 }
1938
1939 return NULL;
1940}
1941
1942static void pairing_complete(struct pending_cmd *cmd, u8 status)
1943{
1944 struct mgmt_rp_pair_device rp;
1945 struct hci_conn *conn = cmd->user_data;
1946
Johan Hedbergba4e5642011-11-11 00:07:34 +02001947 bacpy(&rp.addr.bdaddr, &conn->dst);
1948 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001949
Johan Hedbergaee9b212012-02-18 15:07:59 +02001950 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1951 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001952
1953 /* So we don't get further callbacks for this connection */
1954 conn->connect_cfm_cb = NULL;
1955 conn->security_cfm_cb = NULL;
1956 conn->disconn_cfm_cb = NULL;
1957
1958 hci_conn_put(conn);
1959
Johan Hedberga664b5b2011-02-19 12:06:02 -03001960 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001961}
1962
1963static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1964{
1965 struct pending_cmd *cmd;
1966
1967 BT_DBG("status %u", status);
1968
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001969 cmd = find_pairing(conn);
1970 if (!cmd)
1971 BT_DBG("Unable to find a pending command");
1972 else
Johan Hedberge2113262012-02-18 15:20:03 +02001973 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001974}
1975
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001976static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001977{
1978 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001979 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001980 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001981 struct pending_cmd *cmd;
1982 u8 sec_level, auth_type;
1983 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001984 int err;
1985
1986 BT_DBG("");
1987
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001988 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001989 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1990 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001991
Szymon Janc4e51eae2011-02-25 19:05:48 +01001992 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001993 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001994 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1995 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001996
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001997 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001998
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001999 sec_level = BT_SECURITY_MEDIUM;
2000 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002001 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002002 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002003 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002004
Johan Hedbergba4e5642011-11-11 00:07:34 +02002005 if (cp->addr.type == MGMT_ADDR_BREDR)
2006 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002007 auth_type);
2008 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002009 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002010 auth_type);
2011
Johan Hedberg1425acb2011-11-11 00:07:35 +02002012 memset(&rp, 0, sizeof(rp));
2013 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2014 rp.addr.type = cp->addr.type;
2015
Ville Tervo30e76272011-02-22 16:10:53 -03002016 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002017 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2018 MGMT_STATUS_CONNECT_FAILED,
2019 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002020 goto unlock;
2021 }
2022
2023 if (conn->connect_cfm_cb) {
2024 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002025 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2026 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002027 goto unlock;
2028 }
2029
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002030 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002031 if (!cmd) {
2032 err = -ENOMEM;
2033 hci_conn_put(conn);
2034 goto unlock;
2035 }
2036
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002037 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002038 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002039 conn->connect_cfm_cb = pairing_complete_cb;
2040
Johan Hedberge9a416b2011-02-19 12:05:56 -03002041 conn->security_cfm_cb = pairing_complete_cb;
2042 conn->disconn_cfm_cb = pairing_complete_cb;
2043 conn->io_capability = cp->io_cap;
2044 cmd->user_data = conn;
2045
2046 if (conn->state == BT_CONNECTED &&
2047 hci_conn_security(conn, sec_level, auth_type))
2048 pairing_complete(cmd, 0);
2049
2050 err = 0;
2051
2052unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002053 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002054 hci_dev_put(hdev);
2055
2056 return err;
2057}
2058
Johan Hedberg28424702012-02-02 04:02:29 +02002059static int cancel_pair_device(struct sock *sk, u16 index,
2060 unsigned char *data, u16 len)
2061{
2062 struct mgmt_addr_info *addr = (void *) data;
2063 struct hci_dev *hdev;
2064 struct pending_cmd *cmd;
2065 struct hci_conn *conn;
2066 int err;
2067
2068 BT_DBG("");
2069
2070 if (len != sizeof(*addr))
2071 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2072 MGMT_STATUS_INVALID_PARAMS);
2073
2074 hdev = hci_dev_get(index);
2075 if (!hdev)
2076 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2077 MGMT_STATUS_INVALID_PARAMS);
2078
2079 hci_dev_lock(hdev);
2080
2081 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2082 if (!cmd) {
2083 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2084 MGMT_STATUS_INVALID_PARAMS);
2085 goto unlock;
2086 }
2087
2088 conn = cmd->user_data;
2089
2090 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2091 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2092 MGMT_STATUS_INVALID_PARAMS);
2093 goto unlock;
2094 }
2095
2096 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2097
Johan Hedbergaee9b212012-02-18 15:07:59 +02002098 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002099 sizeof(*addr));
2100unlock:
2101 hci_dev_unlock(hdev);
2102 hci_dev_put(hdev);
2103
2104 return err;
2105}
2106
Brian Gix0df4c182011-11-16 13:53:13 -08002107static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002108 u8 type, u16 mgmt_op, u16 hci_op,
2109 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002110{
Johan Hedberga5c29682011-02-19 12:05:57 -03002111 struct pending_cmd *cmd;
2112 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002113 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002114 int err;
2115
Szymon Janc4e51eae2011-02-25 19:05:48 +01002116 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002117 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002118 return cmd_status(sk, index, mgmt_op,
2119 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002120
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002121 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002122
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002123 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002124 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2125 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002126 }
2127
Johan Hedberg272d90d2012-02-09 15:26:12 +02002128 if (type == MGMT_ADDR_BREDR)
2129 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2130 else
Brian Gix47c15e22011-11-16 13:53:14 -08002131 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002132
Johan Hedberg272d90d2012-02-09 15:26:12 +02002133 if (!conn) {
2134 err = cmd_status(sk, index, mgmt_op,
2135 MGMT_STATUS_NOT_CONNECTED);
2136 goto done;
2137 }
2138
2139 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002140 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002141 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002142
Brian Gix5fe57d92011-12-21 16:12:13 -08002143 if (!err)
2144 err = cmd_status(sk, index, mgmt_op,
2145 MGMT_STATUS_SUCCESS);
2146 else
2147 err = cmd_status(sk, index, mgmt_op,
2148 MGMT_STATUS_FAILED);
2149
Brian Gix47c15e22011-11-16 13:53:14 -08002150 goto done;
2151 }
2152
Brian Gix0df4c182011-11-16 13:53:13 -08002153 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002154 if (!cmd) {
2155 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002156 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002157 }
2158
Brian Gix0df4c182011-11-16 13:53:13 -08002159 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002160 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2161 struct hci_cp_user_passkey_reply cp;
2162
2163 bacpy(&cp.bdaddr, bdaddr);
2164 cp.passkey = passkey;
2165 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2166 } else
2167 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2168
Johan Hedberga664b5b2011-02-19 12:06:02 -03002169 if (err < 0)
2170 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002171
Brian Gix0df4c182011-11-16 13:53:13 -08002172done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002173 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002174 hci_dev_put(hdev);
2175
2176 return err;
2177}
2178
Brian Gix0df4c182011-11-16 13:53:13 -08002179static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2180{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002181 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002182
2183 BT_DBG("");
2184
2185 if (len != sizeof(*cp))
2186 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2187 MGMT_STATUS_INVALID_PARAMS);
2188
Johan Hedberg272d90d2012-02-09 15:26:12 +02002189 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2190 MGMT_OP_USER_CONFIRM_REPLY,
2191 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002192}
2193
2194static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2195 u16 len)
2196{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002197 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002198
2199 BT_DBG("");
2200
2201 if (len != sizeof(*cp))
2202 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2203 MGMT_STATUS_INVALID_PARAMS);
2204
Johan Hedberg272d90d2012-02-09 15:26:12 +02002205 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2206 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2207 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002208}
2209
Brian Gix604086b2011-11-23 08:28:33 -08002210static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002213
2214 BT_DBG("");
2215
2216 if (len != sizeof(*cp))
2217 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2218 EINVAL);
2219
Johan Hedberg272d90d2012-02-09 15:26:12 +02002220 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2221 MGMT_OP_USER_PASSKEY_REPLY,
2222 HCI_OP_USER_PASSKEY_REPLY,
2223 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002224}
2225
2226static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2227 u16 len)
2228{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002229 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002230
2231 BT_DBG("");
2232
2233 if (len != sizeof(*cp))
2234 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2235 EINVAL);
2236
Johan Hedberg272d90d2012-02-09 15:26:12 +02002237 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2238 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2239 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002240}
2241
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002242static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002243 u16 len)
2244{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002245 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002246 struct hci_cp_write_local_name hci_cp;
2247 struct hci_dev *hdev;
2248 struct pending_cmd *cmd;
2249 int err;
2250
2251 BT_DBG("");
2252
2253 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002254 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2255 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002256
2257 hdev = hci_dev_get(index);
2258 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002259 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2260 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002261
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002262 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002263
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002264 memcpy(hdev->short_name, mgmt_cp->short_name,
2265 sizeof(hdev->short_name));
2266
Johan Hedbergb5235a62012-02-21 14:32:24 +02002267 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002268 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2269
2270 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2271 data, len);
2272 if (err < 0)
2273 goto failed;
2274
2275 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2276 sk);
2277
Johan Hedbergb5235a62012-02-21 14:32:24 +02002278 goto failed;
2279 }
2280
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002281 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002282 if (!cmd) {
2283 err = -ENOMEM;
2284 goto failed;
2285 }
2286
2287 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2288 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2289 &hci_cp);
2290 if (err < 0)
2291 mgmt_pending_remove(cmd);
2292
2293failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002294 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002295 hci_dev_put(hdev);
2296
2297 return err;
2298}
2299
Szymon Jancc35938b2011-03-22 13:12:21 +01002300static int read_local_oob_data(struct sock *sk, u16 index)
2301{
2302 struct hci_dev *hdev;
2303 struct pending_cmd *cmd;
2304 int err;
2305
2306 BT_DBG("hci%u", index);
2307
2308 hdev = hci_dev_get(index);
2309 if (!hdev)
2310 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002311 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002312
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002313 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002314
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002315 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002316 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002317 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002318 goto unlock;
2319 }
2320
2321 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2322 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002323 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002324 goto unlock;
2325 }
2326
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002327 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002328 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2329 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002330 goto unlock;
2331 }
2332
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002333 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002334 if (!cmd) {
2335 err = -ENOMEM;
2336 goto unlock;
2337 }
2338
2339 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2340 if (err < 0)
2341 mgmt_pending_remove(cmd);
2342
2343unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002344 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002345 hci_dev_put(hdev);
2346
2347 return err;
2348}
2349
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002350static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2351 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002352{
2353 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002354 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002355 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002356 int err;
2357
2358 BT_DBG("hci%u ", index);
2359
2360 if (len != sizeof(*cp))
2361 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002362 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002363
2364 hdev = hci_dev_get(index);
2365 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002366 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2367 MGMT_STATUS_INVALID_PARAMS,
2368 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002369
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002370 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002371
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002372 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002373 cp->randomizer);
2374 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002375 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002376 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002377 status = 0;
2378
2379 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2380 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002381
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002382 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002383 hci_dev_put(hdev);
2384
2385 return err;
2386}
2387
2388static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002389 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002390{
2391 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002392 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002393 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002394 int err;
2395
2396 BT_DBG("hci%u ", index);
2397
2398 if (len != sizeof(*cp))
2399 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002400 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002401
2402 hdev = hci_dev_get(index);
2403 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002404 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2405 MGMT_STATUS_INVALID_PARAMS,
2406 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002407
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002408 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002409
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002410 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002411 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002412 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002413 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002414 status = 0;
2415
2416 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2417 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002418
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002419 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002420 hci_dev_put(hdev);
2421
2422 return err;
2423}
2424
Andre Guedes5e0452c2012-02-17 20:39:38 -03002425static int discovery(struct hci_dev *hdev)
2426{
2427 int err;
2428
2429 if (lmp_host_le_capable(hdev)) {
2430 if (lmp_bredr_capable(hdev)) {
2431 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2432 LE_SCAN_INT, LE_SCAN_WIN,
2433 LE_SCAN_TIMEOUT_BREDR_LE);
2434 } else {
2435 hdev->discovery.type = DISCOV_TYPE_LE;
2436 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2437 LE_SCAN_INT, LE_SCAN_WIN,
2438 LE_SCAN_TIMEOUT_LE_ONLY);
2439 }
2440 } else {
2441 hdev->discovery.type = DISCOV_TYPE_BREDR;
2442 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2443 }
2444
2445 return err;
2446}
2447
2448int mgmt_interleaved_discovery(struct hci_dev *hdev)
2449{
2450 int err;
2451
2452 BT_DBG("%s", hdev->name);
2453
2454 hci_dev_lock(hdev);
2455
2456 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2457 if (err < 0)
2458 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2459
2460 hci_dev_unlock(hdev);
2461
2462 return err;
2463}
2464
Johan Hedberg450dfda2011-11-12 11:58:22 +02002465static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002466 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002467{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002468 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002469 struct pending_cmd *cmd;
2470 struct hci_dev *hdev;
2471 int err;
2472
2473 BT_DBG("hci%u", index);
2474
Johan Hedberg450dfda2011-11-12 11:58:22 +02002475 if (len != sizeof(*cp))
2476 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2477 MGMT_STATUS_INVALID_PARAMS);
2478
Johan Hedberg14a53662011-04-27 10:29:56 -04002479 hdev = hci_dev_get(index);
2480 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002481 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2482 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002483
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002484 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002485
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002486 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002487 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2488 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002489 goto failed;
2490 }
2491
Johan Hedbergff9ef572012-01-04 14:23:45 +02002492 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2493 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2494 MGMT_STATUS_BUSY);
2495 goto failed;
2496 }
2497
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002498 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002499 if (!cmd) {
2500 err = -ENOMEM;
2501 goto failed;
2502 }
2503
Andre Guedes4aab14e2012-02-17 20:39:36 -03002504 hdev->discovery.type = cp->type;
2505
2506 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002507 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002508 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002509 break;
2510
2511 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002512 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2513 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002514 break;
2515
Andre Guedes5e0452c2012-02-17 20:39:38 -03002516 case DISCOV_TYPE_INTERLEAVED:
2517 err = discovery(hdev);
2518 break;
2519
Andre Guedesf39799f2012-02-17 20:39:35 -03002520 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002521 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002522 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002523
Johan Hedberg14a53662011-04-27 10:29:56 -04002524 if (err < 0)
2525 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002526 else
2527 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002528
2529failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002530 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002531 hci_dev_put(hdev);
2532
2533 return err;
2534}
2535
Johan Hedbergd9306502012-02-20 23:25:18 +02002536static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002537{
Johan Hedbergd9306502012-02-20 23:25:18 +02002538 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002539 struct hci_dev *hdev;
2540 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002541 struct hci_cp_remote_name_req_cancel cp;
2542 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002543 int err;
2544
2545 BT_DBG("hci%u", index);
2546
Johan Hedbergd9306502012-02-20 23:25:18 +02002547 if (len != sizeof(*mgmt_cp))
2548 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2549 MGMT_STATUS_INVALID_PARAMS);
2550
Johan Hedberg14a53662011-04-27 10:29:56 -04002551 hdev = hci_dev_get(index);
2552 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002553 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2554 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002555
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002556 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002557
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002558 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002559 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2560 MGMT_STATUS_REJECTED,
2561 &mgmt_cp->type, sizeof(mgmt_cp->type));
2562 goto unlock;
2563 }
2564
2565 if (hdev->discovery.type != mgmt_cp->type) {
2566 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2567 MGMT_STATUS_INVALID_PARAMS,
2568 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002569 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002570 }
2571
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002572 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002573 if (!cmd) {
2574 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002575 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002576 }
2577
Andre Guedes343f9352012-02-17 20:39:37 -03002578 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002579 err = hci_cancel_inquiry(hdev);
2580 if (err < 0)
2581 mgmt_pending_remove(cmd);
2582 else
2583 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2584 goto unlock;
2585 }
2586
2587 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2588 if (!e) {
2589 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002590 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002591 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002592 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2593 goto unlock;
2594 }
2595
2596 bacpy(&cp.bdaddr, &e->data.bdaddr);
2597 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2598 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002599 if (err < 0)
2600 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002601 else
2602 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002603
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002604unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002605 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002606 hci_dev_put(hdev);
2607
2608 return err;
2609}
2610
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002611static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002612{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002613 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002614 struct inquiry_entry *e;
2615 struct hci_dev *hdev;
2616 int err;
2617
2618 BT_DBG("hci%u", index);
2619
2620 if (len != sizeof(*cp))
2621 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2622 MGMT_STATUS_INVALID_PARAMS);
2623
2624 hdev = hci_dev_get(index);
2625 if (!hdev)
2626 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2627 MGMT_STATUS_INVALID_PARAMS);
2628
2629 hci_dev_lock(hdev);
2630
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002631 if (!hci_discovery_active(hdev)) {
2632 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2633 MGMT_STATUS_FAILED);
2634 goto failed;
2635 }
2636
Johan Hedberga198e7b2012-02-17 14:27:06 +02002637 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002638 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002639 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002640 MGMT_STATUS_INVALID_PARAMS);
2641 goto failed;
2642 }
2643
2644 if (cp->name_known) {
2645 e->name_state = NAME_KNOWN;
2646 list_del(&e->list);
2647 } else {
2648 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002649 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002650 }
2651
2652 err = 0;
2653
2654failed:
2655 hci_dev_unlock(hdev);
2656
2657 return err;
2658}
2659
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002660static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002661{
2662 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002663 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002664 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002665 int err;
2666
2667 BT_DBG("hci%u", index);
2668
Antti Julku7fbec222011-06-15 12:01:15 +03002669 if (len != sizeof(*cp))
2670 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002671 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002672
2673 hdev = hci_dev_get(index);
2674 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002675 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2676 MGMT_STATUS_INVALID_PARAMS,
2677 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002678
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002679 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002680
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002681 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002682 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002683 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002684 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002685 status = 0;
2686
2687 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2688 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002690 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002691 hci_dev_put(hdev);
2692
2693 return err;
2694}
2695
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002696static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002697{
2698 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002699 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002700 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002701 int err;
2702
2703 BT_DBG("hci%u", index);
2704
Antti Julku7fbec222011-06-15 12:01:15 +03002705 if (len != sizeof(*cp))
2706 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002707 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002708
2709 hdev = hci_dev_get(index);
2710 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002711 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2712 MGMT_STATUS_INVALID_PARAMS,
2713 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002715 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002716
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002717 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002718 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002719 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002720 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002721 status = 0;
2722
2723 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2724 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002725
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002726 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002727 hci_dev_put(hdev);
2728
2729 return err;
2730}
2731
Antti Julkuf6422ec2011-06-22 13:11:56 +03002732static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002733 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002734{
2735 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002736 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002737 struct hci_cp_write_page_scan_activity acp;
2738 u8 type;
2739 int err;
2740
2741 BT_DBG("hci%u", index);
2742
2743 if (len != sizeof(*cp))
2744 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002745 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002746
2747 hdev = hci_dev_get(index);
2748 if (!hdev)
2749 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002751 if (!hdev_is_powered(hdev))
2752 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2753 MGMT_STATUS_NOT_POWERED);
2754
2755 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2756 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2757 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002758
2759 hci_dev_lock(hdev);
2760
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002761 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002762 type = PAGE_SCAN_TYPE_INTERLACED;
2763 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2764 } else {
2765 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2766 acp.interval = 0x0800; /* default 1.28 sec page scan */
2767 }
2768
2769 acp.window = 0x0012; /* default 11.25 msec page scan window */
2770
2771 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2772 sizeof(acp), &acp);
2773 if (err < 0) {
2774 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002775 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002776 goto done;
2777 }
2778
2779 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2780 if (err < 0) {
2781 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002782 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002783 goto done;
2784 }
2785
Johan Hedbergaee9b212012-02-18 15:07:59 +02002786 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2787 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002788done:
2789 hci_dev_unlock(hdev);
2790 hci_dev_put(hdev);
2791
2792 return err;
2793}
2794
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002795static int load_long_term_keys(struct sock *sk, u16 index,
2796 void *cp_data, u16 len)
2797{
2798 struct hci_dev *hdev;
2799 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2800 u16 key_count, expected_len;
2801 int i;
2802
2803 if (len < sizeof(*cp))
2804 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2805 EINVAL);
2806
2807 key_count = get_unaligned_le16(&cp->key_count);
2808
2809 expected_len = sizeof(*cp) + key_count *
2810 sizeof(struct mgmt_ltk_info);
2811 if (expected_len != len) {
2812 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2813 len, expected_len);
2814 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2815 EINVAL);
2816 }
2817
2818 hdev = hci_dev_get(index);
2819 if (!hdev)
2820 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2821 ENODEV);
2822
2823 BT_DBG("hci%u key_count %u", index, key_count);
2824
2825 hci_dev_lock(hdev);
2826
2827 hci_smp_ltks_clear(hdev);
2828
2829 for (i = 0; i < key_count; i++) {
2830 struct mgmt_ltk_info *key = &cp->keys[i];
2831 u8 type;
2832
2833 if (key->master)
2834 type = HCI_SMP_LTK;
2835 else
2836 type = HCI_SMP_LTK_SLAVE;
2837
2838 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2839 type, 0, key->authenticated, key->val,
2840 key->enc_size, key->ediv, key->rand);
2841 }
2842
2843 hci_dev_unlock(hdev);
2844 hci_dev_put(hdev);
2845
2846 return 0;
2847}
2848
Johan Hedberg03811012010-12-08 00:21:06 +02002849int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2850{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002851 void *buf;
2852 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002853 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002854 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002855 int err;
2856
2857 BT_DBG("got %zu bytes", msglen);
2858
2859 if (msglen < sizeof(*hdr))
2860 return -EINVAL;
2861
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002862 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002863 if (!buf)
2864 return -ENOMEM;
2865
2866 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2867 err = -EFAULT;
2868 goto done;
2869 }
2870
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002871 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002872 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002873 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002874 len = get_unaligned_le16(&hdr->len);
2875
2876 if (len != msglen - sizeof(*hdr)) {
2877 err = -EINVAL;
2878 goto done;
2879 }
2880
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002881 cp = buf + sizeof(*hdr);
2882
Johan Hedberg03811012010-12-08 00:21:06 +02002883 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002884 case MGMT_OP_READ_VERSION:
2885 err = read_version(sk);
2886 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002887 case MGMT_OP_READ_COMMANDS:
2888 err = read_commands(sk);
2889 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002890 case MGMT_OP_READ_INDEX_LIST:
2891 err = read_index_list(sk);
2892 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002893 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002894 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002895 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002896 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002897 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002898 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002899 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002900 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002901 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002902 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002903 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002904 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002905 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002906 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002907 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002908 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002909 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002910 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002911 case MGMT_OP_SET_LINK_SECURITY:
2912 err = set_link_security(sk, index, cp, len);
2913 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002914 case MGMT_OP_SET_SSP:
2915 err = set_ssp(sk, index, cp, len);
2916 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002917 case MGMT_OP_SET_HS:
2918 err = set_hs(sk, index, cp, len);
2919 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002920 case MGMT_OP_SET_LE:
2921 err = set_le(sk, index, cp, len);
2922 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002923 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002924 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002925 break;
2926 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002927 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002928 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002929 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002930 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002931 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002932 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002933 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002934 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002935 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002936 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002937 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002938 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002939 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002940 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002941 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002942 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002943 break;
2944 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002945 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002946 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002947 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002948 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002949 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002950 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002951 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002952 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002953 case MGMT_OP_CANCEL_PAIR_DEVICE:
2954 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2955 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002956 case MGMT_OP_UNPAIR_DEVICE:
2957 err = unpair_device(sk, index, cp, len);
2958 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002959 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002960 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002961 break;
2962 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002963 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002964 break;
Brian Gix604086b2011-11-23 08:28:33 -08002965 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002966 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002967 break;
2968 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002969 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002970 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002971 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002972 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002973 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002974 case MGMT_OP_READ_LOCAL_OOB_DATA:
2975 err = read_local_oob_data(sk, index);
2976 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002977 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002978 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002979 break;
2980 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002981 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002982 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002983 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002984 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002985 break;
2986 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002987 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002988 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002989 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002990 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002991 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002992 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002993 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002994 break;
2995 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002996 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002997 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002998 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2999 err = load_long_term_keys(sk, index, cp, len);
3000 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003001 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003002 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003003 err = cmd_status(sk, index, opcode,
3004 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003005 break;
3006 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003007
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003008 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003009 goto done;
3010
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003011 err = msglen;
3012
3013done:
3014 kfree(buf);
3015 return err;
3016}
3017
Johan Hedbergb24752f2011-11-03 14:40:33 +02003018static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3019{
3020 u8 *status = data;
3021
3022 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3023 mgmt_pending_remove(cmd);
3024}
3025
Johan Hedberg744cf192011-11-08 20:40:14 +02003026int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003027{
Johan Hedberg744cf192011-11-08 20:40:14 +02003028 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003029}
3030
Johan Hedberg744cf192011-11-08 20:40:14 +02003031int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003032{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003033 u8 status = ENODEV;
3034
Johan Hedberg744cf192011-11-08 20:40:14 +02003035 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003036
Johan Hedberg744cf192011-11-08 20:40:14 +02003037 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003038}
3039
3040struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003041 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003042 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003043};
3044
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003045static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003046{
Johan Hedberg03811012010-12-08 00:21:06 +02003047 struct cmd_lookup *match = data;
3048
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003049 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003050
3051 list_del(&cmd->list);
3052
3053 if (match->sk == NULL) {
3054 match->sk = cmd->sk;
3055 sock_hold(match->sk);
3056 }
3057
3058 mgmt_pending_free(cmd);
3059}
3060
Johan Hedberg744cf192011-11-08 20:40:14 +02003061int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003062{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003063 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003064 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003065
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003066 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3067 return 0;
3068
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003069 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003070
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003071 if (powered) {
3072 u8 scan = 0;
3073
3074 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3075 scan |= SCAN_PAGE;
3076 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3077 scan |= SCAN_INQUIRY;
3078
3079 if (scan)
3080 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3081 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003082 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003083 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003084 }
3085
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003086 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003087
3088 if (match.sk)
3089 sock_put(match.sk);
3090
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003091 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003092}
3093
Johan Hedberg744cf192011-11-08 20:40:14 +02003094int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003095{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003096 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003097 bool changed = false;
3098 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003099
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003100 if (discoverable) {
3101 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3102 changed = true;
3103 } else {
3104 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3105 changed = true;
3106 }
Johan Hedberg03811012010-12-08 00:21:06 +02003107
Johan Hedberged9b5f22012-02-21 20:47:06 +02003108 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3109 &match);
3110
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003111 if (changed)
3112 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003113
Johan Hedberg03811012010-12-08 00:21:06 +02003114 if (match.sk)
3115 sock_put(match.sk);
3116
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003117 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003118}
3119
Johan Hedberg744cf192011-11-08 20:40:14 +02003120int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003121{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003122 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003123 bool changed = false;
3124 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003125
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003126 if (connectable) {
3127 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3128 changed = true;
3129 } else {
3130 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3131 changed = true;
3132 }
Johan Hedberg03811012010-12-08 00:21:06 +02003133
Johan Hedberged9b5f22012-02-21 20:47:06 +02003134 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3135 &match);
3136
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003137 if (changed)
3138 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003139
3140 if (match.sk)
3141 sock_put(match.sk);
3142
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003143 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003144}
3145
Johan Hedberg744cf192011-11-08 20:40:14 +02003146int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003147{
Johan Hedbergca69b792011-11-11 18:10:00 +02003148 u8 mgmt_err = mgmt_status(status);
3149
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003150 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003151 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003152 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003153
3154 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003155 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003156 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003157
3158 return 0;
3159}
3160
Johan Hedberg744cf192011-11-08 20:40:14 +02003161int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3162 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003163{
Johan Hedberg86742e12011-11-07 23:13:38 +02003164 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003165
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003166 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003167
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003168 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003169 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3170 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003171 ev.key.type = key->type;
3172 memcpy(ev.key.val, key->val, 16);
3173 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003174
Johan Hedberg744cf192011-11-08 20:40:14 +02003175 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003176}
Johan Hedbergf7520542011-01-20 12:34:39 +02003177
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003178int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3179{
3180 struct mgmt_ev_new_long_term_key ev;
3181
3182 memset(&ev, 0, sizeof(ev));
3183
3184 ev.store_hint = persistent;
3185 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3186 ev.key.addr.type = key->bdaddr_type;
3187 ev.key.authenticated = key->authenticated;
3188 ev.key.enc_size = key->enc_size;
3189 ev.key.ediv = key->ediv;
3190
3191 if (key->type == HCI_SMP_LTK)
3192 ev.key.master = 1;
3193
3194 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3195 memcpy(ev.key.val, key->val, sizeof(key->val));
3196
3197 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3198 &ev, sizeof(ev), NULL);
3199}
3200
Johan Hedbergafc747a2012-01-15 18:11:07 +02003201int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003202 u8 addr_type, u8 *name, u8 name_len,
3203 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003204{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003205 char buf[512];
3206 struct mgmt_ev_device_connected *ev = (void *) buf;
3207 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003208
Johan Hedbergb644ba32012-01-17 21:48:47 +02003209 bacpy(&ev->addr.bdaddr, bdaddr);
3210 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003211
Johan Hedbergb644ba32012-01-17 21:48:47 +02003212 if (name_len > 0)
3213 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3214 name, name_len);
3215
3216 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3217 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3218 EIR_CLASS_OF_DEV, dev_class, 3);
3219
3220 put_unaligned_le16(eir_len, &ev->eir_len);
3221
3222 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3223 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003224}
3225
Johan Hedberg8962ee72011-01-20 12:40:27 +02003226static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3227{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003228 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003229 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003230 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003231
Johan Hedberg88c3df12012-02-09 14:27:38 +02003232 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3233 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003234
Johan Hedbergaee9b212012-02-18 15:07:59 +02003235 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3236 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003237
3238 *sk = cmd->sk;
3239 sock_hold(*sk);
3240
Johan Hedberga664b5b2011-02-19 12:06:02 -03003241 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003242}
3243
Johan Hedberg124f6e32012-02-09 13:50:12 +02003244static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003245{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003246 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003247 struct mgmt_cp_unpair_device *cp = cmd->param;
3248 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003249
3250 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003251 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3252 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003253
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003254 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3255
Johan Hedbergaee9b212012-02-18 15:07:59 +02003256 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003257
3258 mgmt_pending_remove(cmd);
3259}
3260
Johan Hedbergafc747a2012-01-15 18:11:07 +02003261int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3262 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003263{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003264 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003265 struct sock *sk = NULL;
3266 int err;
3267
Johan Hedberg744cf192011-11-08 20:40:14 +02003268 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003269
Johan Hedbergf7520542011-01-20 12:34:39 +02003270 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003271 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003272
Johan Hedbergafc747a2012-01-15 18:11:07 +02003273 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3274 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003275
3276 if (sk)
3277 sock_put(sk);
3278
Johan Hedberg124f6e32012-02-09 13:50:12 +02003279 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003280 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003281
Johan Hedberg8962ee72011-01-20 12:40:27 +02003282 return err;
3283}
3284
Johan Hedberg88c3df12012-02-09 14:27:38 +02003285int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3286 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003287{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003288 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003289 struct pending_cmd *cmd;
3290 int err;
3291
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003292 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003293 if (!cmd)
3294 return -ENOENT;
3295
Johan Hedberg88c3df12012-02-09 14:27:38 +02003296 bacpy(&rp.addr.bdaddr, bdaddr);
3297 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003298
Johan Hedberg88c3df12012-02-09 14:27:38 +02003299 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003300 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003301
Johan Hedberga664b5b2011-02-19 12:06:02 -03003302 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003303
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003304 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3305 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003306 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003307}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003308
Johan Hedberg48264f02011-11-09 13:58:58 +02003309int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3310 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003311{
3312 struct mgmt_ev_connect_failed ev;
3313
Johan Hedberg4c659c32011-11-07 23:13:39 +02003314 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003315 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003316 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003317
Johan Hedberg744cf192011-11-08 20:40:14 +02003318 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003319}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003320
Johan Hedberg744cf192011-11-08 20:40:14 +02003321int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003322{
3323 struct mgmt_ev_pin_code_request ev;
3324
Johan Hedbergd8457692012-02-17 14:24:57 +02003325 bacpy(&ev.addr.bdaddr, bdaddr);
3326 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003327 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003328
Johan Hedberg744cf192011-11-08 20:40:14 +02003329 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003330 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003331}
3332
Johan Hedberg744cf192011-11-08 20:40:14 +02003333int mgmt_pin_code_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_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 Hedbergaee9b212012-02-18 15:07:59 +02003347 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_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}
3354
Johan Hedberg744cf192011-11-08 20:40:14 +02003355int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3356 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003357{
3358 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003359 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003360 int err;
3361
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003362 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003363 if (!cmd)
3364 return -ENOENT;
3365
Johan Hedbergd8457692012-02-17 14:24:57 +02003366 bacpy(&rp.addr.bdaddr, bdaddr);
3367 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003368
Johan Hedbergaee9b212012-02-18 15:07:59 +02003369 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3370 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003371
Johan Hedberga664b5b2011-02-19 12:06:02 -03003372 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003373
3374 return err;
3375}
Johan Hedberga5c29682011-02-19 12:05:57 -03003376
Johan Hedberg744cf192011-11-08 20:40:14 +02003377int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003378 u8 link_type, u8 addr_type, __le32 value,
3379 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003380{
3381 struct mgmt_ev_user_confirm_request ev;
3382
Johan Hedberg744cf192011-11-08 20:40:14 +02003383 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003384
Johan Hedberg272d90d2012-02-09 15:26:12 +02003385 bacpy(&ev.addr.bdaddr, bdaddr);
3386 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003387 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003388 put_unaligned_le32(value, &ev.value);
3389
Johan Hedberg744cf192011-11-08 20:40:14 +02003390 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003391 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003392}
3393
Johan Hedberg272d90d2012-02-09 15:26:12 +02003394int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3395 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003396{
3397 struct mgmt_ev_user_passkey_request ev;
3398
3399 BT_DBG("%s", hdev->name);
3400
Johan Hedberg272d90d2012-02-09 15:26:12 +02003401 bacpy(&ev.addr.bdaddr, bdaddr);
3402 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003403
3404 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3405 NULL);
3406}
3407
Brian Gix0df4c182011-11-16 13:53:13 -08003408static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003409 u8 link_type, u8 addr_type, u8 status,
3410 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003411{
3412 struct pending_cmd *cmd;
3413 struct mgmt_rp_user_confirm_reply rp;
3414 int err;
3415
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003416 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003417 if (!cmd)
3418 return -ENOENT;
3419
Johan Hedberg272d90d2012-02-09 15:26:12 +02003420 bacpy(&rp.addr.bdaddr, bdaddr);
3421 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003422 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3423 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003424
Johan Hedberga664b5b2011-02-19 12:06:02 -03003425 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003426
3427 return err;
3428}
3429
Johan Hedberg744cf192011-11-08 20:40:14 +02003430int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003431 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003432{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003433 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3434 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003435}
3436
Johan Hedberg272d90d2012-02-09 15:26:12 +02003437int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3438 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003439{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003440 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3441 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003442}
Johan Hedberg2a611692011-02-19 12:06:00 -03003443
Brian Gix604086b2011-11-23 08:28:33 -08003444int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003445 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003446{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003447 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3448 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003449}
3450
Johan Hedberg272d90d2012-02-09 15:26:12 +02003451int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3452 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003453{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003454 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3455 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003456}
3457
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003458int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3459 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003460{
3461 struct mgmt_ev_auth_failed ev;
3462
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003463 bacpy(&ev.addr.bdaddr, bdaddr);
3464 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003465 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003466
Johan Hedberg744cf192011-11-08 20:40:14 +02003467 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003468}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003469
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003470int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3471{
3472 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003473 bool changed = false;
3474 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003475
3476 if (status) {
3477 u8 mgmt_err = mgmt_status(status);
3478 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3479 cmd_status_rsp, &mgmt_err);
3480 return 0;
3481 }
3482
Johan Hedberg47990ea2012-02-22 11:58:37 +02003483 if (test_bit(HCI_AUTH, &hdev->flags)) {
3484 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3485 changed = true;
3486 } else {
3487 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3488 changed = true;
3489 }
3490
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003491 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3492 &match);
3493
Johan Hedberg47990ea2012-02-22 11:58:37 +02003494 if (changed)
3495 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003496
3497 if (match.sk)
3498 sock_put(match.sk);
3499
3500 return err;
3501}
3502
Johan Hedbergcacaf522012-02-21 00:52:42 +02003503static int clear_eir(struct hci_dev *hdev)
3504{
3505 struct hci_cp_write_eir cp;
3506
3507 if (!(hdev->features[6] & LMP_EXT_INQ))
3508 return 0;
3509
Johan Hedbergc80da272012-02-22 15:38:48 +02003510 memset(hdev->eir, 0, sizeof(hdev->eir));
3511
Johan Hedbergcacaf522012-02-21 00:52:42 +02003512 memset(&cp, 0, sizeof(cp));
3513
3514 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3515}
3516
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003517int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003518{
3519 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003520 bool changed = false;
3521 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003522
3523 if (status) {
3524 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003525
3526 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3527 &hdev->dev_flags))
3528 err = new_settings(hdev, NULL);
3529
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003530 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3531 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003532
3533 return err;
3534 }
3535
3536 if (enable) {
3537 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3538 changed = true;
3539 } else {
3540 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3541 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003542 }
3543
3544 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3545
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003546 if (changed)
3547 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003548
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003549 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003550 sock_put(match.sk);
3551
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003552 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3553 update_eir(hdev);
3554 else
3555 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003556
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003557 return err;
3558}
3559
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003560int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3561 u8 status)
3562{
3563 int err;
3564
3565 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
3566
3567 return err;
3568}
3569
Johan Hedberg744cf192011-11-08 20:40:14 +02003570int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003571{
3572 struct pending_cmd *cmd;
3573 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003574 bool changed = false;
3575 int err = 0;
3576
3577 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3578 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3579 changed = true;
3580 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003581
3582 memset(&ev, 0, sizeof(ev));
3583 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003584 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003585
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003586 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003587 if (!cmd)
3588 goto send_event;
3589
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003590 /* Always assume that either the short or the complete name has
3591 * changed if there was a pending mgmt command */
3592 changed = true;
3593
Johan Hedbergb312b1612011-03-16 14:29:37 +02003594 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003595 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003596 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003597 goto failed;
3598 }
3599
Johan Hedbergaee9b212012-02-18 15:07:59 +02003600 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003601 sizeof(ev));
3602 if (err < 0)
3603 goto failed;
3604
3605send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003606 if (changed)
3607 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3608 sizeof(ev), cmd ? cmd->sk : NULL);
3609
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003610 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003611
3612failed:
3613 if (cmd)
3614 mgmt_pending_remove(cmd);
3615 return err;
3616}
Szymon Jancc35938b2011-03-22 13:12:21 +01003617
Johan Hedberg744cf192011-11-08 20:40:14 +02003618int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3619 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003620{
3621 struct pending_cmd *cmd;
3622 int err;
3623
Johan Hedberg744cf192011-11-08 20:40:14 +02003624 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003625
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003626 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003627 if (!cmd)
3628 return -ENOENT;
3629
3630 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003631 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003632 MGMT_OP_READ_LOCAL_OOB_DATA,
3633 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003634 } else {
3635 struct mgmt_rp_read_local_oob_data rp;
3636
3637 memcpy(rp.hash, hash, sizeof(rp.hash));
3638 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3639
Johan Hedberg744cf192011-11-08 20:40:14 +02003640 err = cmd_complete(cmd->sk, hdev->id,
3641 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003642 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003643 }
3644
3645 mgmt_pending_remove(cmd);
3646
3647 return err;
3648}
Johan Hedberge17acd42011-03-30 23:57:16 +03003649
Johan Hedberg06199cf2012-02-22 16:37:11 +02003650int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3651{
3652 struct cmd_lookup match = { NULL, hdev };
3653 bool changed = false;
3654 int err = 0;
3655
3656 if (status) {
3657 u8 mgmt_err = mgmt_status(status);
3658
3659 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3660 &hdev->dev_flags))
3661 err = new_settings(hdev, NULL);
3662
3663 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3664 cmd_status_rsp, &mgmt_err);
3665
3666 return err;
3667 }
3668
3669 if (enable) {
3670 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3671 changed = true;
3672 } else {
3673 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3674 changed = true;
3675 }
3676
3677 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3678
3679 if (changed)
3680 err = new_settings(hdev, match.sk);
3681
3682 if (match.sk)
3683 sock_put(match.sk);
3684
3685 return err;
3686}
3687
Johan Hedberg48264f02011-11-09 13:58:58 +02003688int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003689 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003690 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003691{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003692 char buf[512];
3693 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003694 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003695
Johan Hedberg1dc06092012-01-15 21:01:23 +02003696 /* Leave 5 bytes for a potential CoD field */
3697 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003698 return -EINVAL;
3699
Johan Hedberg1dc06092012-01-15 21:01:23 +02003700 memset(buf, 0, sizeof(buf));
3701
Johan Hedberge319d2e2012-01-15 19:51:59 +02003702 bacpy(&ev->addr.bdaddr, bdaddr);
3703 ev->addr.type = link_to_mgmt(link_type, addr_type);
3704 ev->rssi = rssi;
3705 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003706
Johan Hedberg1dc06092012-01-15 21:01:23 +02003707 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003708 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003709
Johan Hedberg1dc06092012-01-15 21:01:23 +02003710 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3711 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3712 dev_class, 3);
3713
3714 put_unaligned_le16(eir_len, &ev->eir_len);
3715
3716 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003717
Johan Hedberge319d2e2012-01-15 19:51:59 +02003718 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003719}
Johan Hedberga88a9652011-03-30 13:18:12 +03003720
Johan Hedbergb644ba32012-01-17 21:48:47 +02003721int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3722 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003723{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003724 struct mgmt_ev_device_found *ev;
3725 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3726 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003727
Johan Hedbergb644ba32012-01-17 21:48:47 +02003728 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003729
Johan Hedbergb644ba32012-01-17 21:48:47 +02003730 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003731
Johan Hedbergb644ba32012-01-17 21:48:47 +02003732 bacpy(&ev->addr.bdaddr, bdaddr);
3733 ev->addr.type = link_to_mgmt(link_type, addr_type);
3734 ev->rssi = rssi;
3735
3736 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3737 name_len);
3738
3739 put_unaligned_le16(eir_len, &ev->eir_len);
3740
Johan Hedberg053c7e02012-02-04 00:06:00 +02003741 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3742 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003743}
Johan Hedberg314b2382011-04-27 10:29:57 -04003744
Andre Guedes7a135102011-11-09 17:14:25 -03003745int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003746{
3747 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003748 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003749 int err;
3750
Andre Guedes203159d2012-02-13 15:41:01 -03003751 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3752
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003753 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003754 if (!cmd)
3755 return -ENOENT;
3756
Johan Hedbergf808e162012-02-19 12:52:07 +02003757 type = hdev->discovery.type;
3758
3759 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3760 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003761 mgmt_pending_remove(cmd);
3762
3763 return err;
3764}
3765
Andre Guedese6d465c2011-11-09 17:14:26 -03003766int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3767{
3768 struct pending_cmd *cmd;
3769 int err;
3770
3771 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3772 if (!cmd)
3773 return -ENOENT;
3774
Johan Hedbergd9306502012-02-20 23:25:18 +02003775 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3776 &hdev->discovery.type,
3777 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003778 mgmt_pending_remove(cmd);
3779
3780 return err;
3781}
Johan Hedberg314b2382011-04-27 10:29:57 -04003782
Johan Hedberg744cf192011-11-08 20:40:14 +02003783int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003784{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003785 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003786 struct pending_cmd *cmd;
3787
Andre Guedes343fb142011-11-22 17:14:19 -03003788 BT_DBG("%s discovering %u", hdev->name, discovering);
3789
Johan Hedberg164a6e72011-11-01 17:06:44 +02003790 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003791 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003792 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003793 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003794
3795 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003796 u8 type = hdev->discovery.type;
3797
Johan Hedbergd9306502012-02-20 23:25:18 +02003798 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003799 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003800 mgmt_pending_remove(cmd);
3801 }
3802
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003803 memset(&ev, 0, sizeof(ev));
3804 ev.type = hdev->discovery.type;
3805 ev.discovering = discovering;
3806
3807 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003808}
Antti Julku5e762442011-08-25 16:48:02 +03003809
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003810int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003811{
3812 struct pending_cmd *cmd;
3813 struct mgmt_ev_device_blocked ev;
3814
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003815 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003816
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003817 bacpy(&ev.addr.bdaddr, bdaddr);
3818 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003819
Johan Hedberg744cf192011-11-08 20:40:14 +02003820 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3821 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003822}
3823
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003824int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003825{
3826 struct pending_cmd *cmd;
3827 struct mgmt_ev_device_unblocked ev;
3828
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003829 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003830
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003831 bacpy(&ev.addr.bdaddr, bdaddr);
3832 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003833
Johan Hedberg744cf192011-11-08 20:40:14 +02003834 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3835 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003836}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003837
3838module_param(enable_hs, bool, 0644);
3839MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3840
3841module_param(enable_le, bool, 0644);
3842MODULE_PARM_DESC(enable_le, "Enable Low Energy support");