blob: 9c1f7714794d71fb5b8cb1b94701cfe925f60594 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan 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 Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200538 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 return 0;
540
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200541 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
544 memset(&cp, 0, sizeof(cp));
545
546 create_eir(hdev, cp.data);
547
548 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
549 return 0;
550
551 memcpy(hdev->eir, cp.data, sizeof(cp.data));
552
553 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
554}
555
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200556static u8 get_service_classes(struct hci_dev *hdev)
557{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300558 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559 u8 val = 0;
560
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200563
564 return val;
565}
566
567static int update_class(struct hci_dev *hdev)
568{
569 u8 cod[3];
570
571 BT_DBG("%s", hdev->name);
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 return 0;
575
576 cod[0] = hdev->minor_class;
577 cod[1] = hdev->major_class;
578 cod[2] = get_service_classes(hdev);
579
580 if (memcmp(cod, hdev->dev_class, 3) == 0)
581 return 0;
582
583 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
584}
585
Johan Hedberg7d785252011-12-15 00:47:39 +0200586static void service_cache_off(struct work_struct *work)
587{
588 struct hci_dev *hdev = container_of(work, struct hci_dev,
589 service_cache.work);
590
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200591 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200592 return;
593
594 hci_dev_lock(hdev);
595
596 update_eir(hdev);
597 update_class(hdev);
598
599 hci_dev_unlock(hdev);
600}
601
602static void mgmt_init_hdev(struct hci_dev *hdev)
603{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200604 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200605 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
606
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200607 /* Non-mgmt controlled devices get this bit set
608 * implicitly so that pairing works for them, however
609 * for mgmt we require user-space to explicitly enable
610 * it
611 */
612 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
613 }
614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 schedule_delayed_work(&hdev->service_cache,
617 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
618}
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620static int read_controller_info(struct sock *sk, u16 index)
621{
622 struct mgmt_rp_read_info rp;
623 struct hci_dev *hdev;
624
625 BT_DBG("sock %p hci%u", sk, index);
626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_READ_INFO,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
635 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
637 memset(&rp, 0, sizeof(rp));
638
Johan Hedberg03811012010-12-08 00:21:06 +0200639 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200640
641 rp.version = hdev->hci_ver;
642
Johan Hedberg03811012010-12-08 00:21:06 +0200643 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644
645 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
646 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
647
648 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200649
650 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300652 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200653 hci_dev_put(hdev);
654
Johan Hedbergaee9b212012-02-18 15:07:59 +0200655 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200656}
657
658static void mgmt_pending_free(struct pending_cmd *cmd)
659{
660 sock_put(cmd->sk);
661 kfree(cmd->param);
662 kfree(cmd);
663}
664
665static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
666 struct hci_dev *hdev,
667 void *data, u16 len)
668{
669 struct pending_cmd *cmd;
670
671 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
672 if (!cmd)
673 return NULL;
674
675 cmd->opcode = opcode;
676 cmd->index = hdev->id;
677
678 cmd->param = kmalloc(len, GFP_ATOMIC);
679 if (!cmd->param) {
680 kfree(cmd);
681 return NULL;
682 }
683
684 if (data)
685 memcpy(cmd->param, data, len);
686
687 cmd->sk = sk;
688 sock_hold(sk);
689
690 list_add(&cmd->list, &hdev->mgmt_pending);
691
692 return cmd;
693}
694
695static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
696 void (*cb)(struct pending_cmd *cmd, void *data),
697 void *data)
698{
699 struct list_head *p, *n;
700
701 list_for_each_safe(p, n, &hdev->mgmt_pending) {
702 struct pending_cmd *cmd;
703
704 cmd = list_entry(p, struct pending_cmd, list);
705
706 if (opcode > 0 && cmd->opcode != opcode)
707 continue;
708
709 cb(cmd, data);
710 }
711}
712
713static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
714{
715 struct pending_cmd *cmd;
716
717 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
718 if (cmd->opcode == opcode)
719 return cmd;
720 }
721
722 return NULL;
723}
724
725static void mgmt_pending_remove(struct pending_cmd *cmd)
726{
727 list_del(&cmd->list);
728 mgmt_pending_free(cmd);
729}
730
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200731static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200732{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200734
Johan Hedbergaee9b212012-02-18 15:07:59 +0200735 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
736 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200737}
738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300739static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300741 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200742 struct hci_dev *hdev;
743 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
Johan Hedberg03811012010-12-08 00:21:06 +0200746 BT_DBG("request for hci%u", index);
747
748 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200749 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
752 hdev = hci_dev_get(index);
753 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200754 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300757 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100759 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
760 cancel_delayed_work(&hdev->power_off);
761
762 if (cp->val) {
763 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
764 mgmt_powered(hdev, 1);
765 goto failed;
766 }
767 }
768
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200769 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200771 goto failed;
772 }
773
774 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200775 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
776 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200777 goto failed;
778 }
779
780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
781 if (!cmd) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200787 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200789 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200790
791 err = 0;
792
793failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300794 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 hci_dev_put(hdev);
796 return err;
797}
798
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200799static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
800 u16 data_len, struct sock *skip_sk)
801{
802 struct sk_buff *skb;
803 struct mgmt_hdr *hdr;
804
805 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
806 if (!skb)
807 return -ENOMEM;
808
809 hdr = (void *) skb_put(skb, sizeof(*hdr));
810 hdr->opcode = cpu_to_le16(event);
811 if (hdev)
812 hdr->index = cpu_to_le16(hdev->id);
813 else
814 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
815 hdr->len = cpu_to_le16(data_len);
816
817 if (data)
818 memcpy(skb_put(skb, data_len), data, data_len);
819
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100820 /* Time stamp */
821 __net_timestamp(skb);
822
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200823 hci_send_to_control(skb, skip_sk);
824 kfree_skb(skb);
825
826 return 0;
827}
828
829static int new_settings(struct hci_dev *hdev, struct sock *skip)
830{
831 __le32 ev;
832
833 ev = cpu_to_le32(get_current_settings(hdev));
834
835 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
836}
837
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300838static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200839{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300840 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200841 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200842 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200843 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200844 u8 scan;
845 int err;
846
Johan Hedberg03811012010-12-08 00:21:06 +0200847 BT_DBG("request for hci%u", index);
848
849 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200850 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200852
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100853 timeout = get_unaligned_le16(&cp->timeout);
854 if (!cp->val && timeout > 0)
855 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
856 MGMT_STATUS_INVALID_PARAMS);
857
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200858 hdev = hci_dev_get(index);
859 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200860 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
861 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300863 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200864
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200865 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200866 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
867 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200868 goto failed;
869 }
870
871 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
872 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200873 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
874 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200875 goto failed;
876 }
877
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200878 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
879 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
880 MGMT_STATUS_REJECTED);
881 goto failed;
882 }
883
884 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200885 bool changed = false;
886
887 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
888 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
889 changed = true;
890 }
891
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200892 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200893 if (err < 0)
894 goto failed;
895
896 if (changed)
897 err = new_settings(hdev, sk);
898
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200899 goto failed;
900 }
901
902 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100903 if (hdev->discov_timeout > 0) {
904 cancel_delayed_work(&hdev->discov_off);
905 hdev->discov_timeout = 0;
906 }
907
908 if (cp->val && timeout > 0) {
909 hdev->discov_timeout = timeout;
910 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
911 msecs_to_jiffies(hdev->discov_timeout * 1000));
912 }
913
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200914 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200915 goto failed;
916 }
917
918 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
919 if (!cmd) {
920 err = -ENOMEM;
921 goto failed;
922 }
923
924 scan = SCAN_PAGE;
925
926 if (cp->val)
927 scan |= SCAN_INQUIRY;
928 else
929 cancel_delayed_work(&hdev->discov_off);
930
931 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
932 if (err < 0)
933 mgmt_pending_remove(cmd);
934
Johan Hedberg03811012010-12-08 00:21:06 +0200935 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200936 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200937
938failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300939 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200940 hci_dev_put(hdev);
941
942 return err;
943}
944
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300945static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200946{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300947 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200948 struct hci_dev *hdev;
949 struct pending_cmd *cmd;
950 u8 scan;
951 int err;
952
Johan Hedberge41d8b42010-12-13 21:07:03 +0200953 BT_DBG("request for hci%u", index);
954
Johan Hedberg03811012010-12-08 00:21:06 +0200955 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200956 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
957 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200958
959 hdev = hci_dev_get(index);
960 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200961 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
962 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200963
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300964 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200965
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200966 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200967 bool changed = false;
968
969 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
970 changed = true;
971
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200972 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200973 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200974 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
976 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
977 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200978
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200980 if (err < 0)
981 goto failed;
982
983 if (changed)
984 err = new_settings(hdev, sk);
985
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200986 goto failed;
987 }
988
989 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
990 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200991 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
992 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 goto failed;
994 }
995
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200996 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200997 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200998 goto failed;
999 }
1000
1001 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1002 if (!cmd) {
1003 err = -ENOMEM;
1004 goto failed;
1005 }
1006
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001007 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001008 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001009 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001010 scan = 0;
1011
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001012 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1013 hdev->discov_timeout > 0)
1014 cancel_delayed_work(&hdev->discov_off);
1015 }
1016
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1018 if (err < 0)
1019 mgmt_pending_remove(cmd);
1020
1021failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001022 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023 hci_dev_put(hdev);
1024
1025 return err;
1026}
1027
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001028static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001029{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001030 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001031 struct hci_dev *hdev;
1032 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001033
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034 BT_DBG("request for hci%u", index);
1035
1036 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001037 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1038 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001039
1040 hdev = hci_dev_get(index);
1041 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001042 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1043 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001044
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001045 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046
1047 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001048 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001049 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001050 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001051
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001052 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001053 if (err < 0)
1054 goto failed;
1055
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001056 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001057
1058failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001059 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001060 hci_dev_put(hdev);
1061
1062 return err;
1063}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001064
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001065static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1066{
1067 struct mgmt_mode *cp = data;
1068 struct pending_cmd *cmd;
1069 struct hci_dev *hdev;
1070 uint8_t val;
1071 int err;
1072
1073 BT_DBG("request for hci%u", index);
1074
1075 if (len != sizeof(*cp))
1076 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1077 MGMT_STATUS_INVALID_PARAMS);
1078
1079 hdev = hci_dev_get(index);
1080 if (!hdev)
1081 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1082 MGMT_STATUS_INVALID_PARAMS);
1083
1084 hci_dev_lock(hdev);
1085
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001086 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001087 bool changed = false;
1088
1089 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1090 &hdev->dev_flags)) {
1091 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1092 changed = true;
1093 }
1094
1095 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1096 if (err < 0)
1097 goto failed;
1098
1099 if (changed)
1100 err = new_settings(hdev, sk);
1101
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001102 goto failed;
1103 }
1104
1105 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1106 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1107 MGMT_STATUS_BUSY);
1108 goto failed;
1109 }
1110
1111 val = !!cp->val;
1112
1113 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1114 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1115 goto failed;
1116 }
1117
1118 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1119 if (!cmd) {
1120 err = -ENOMEM;
1121 goto failed;
1122 }
1123
1124 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1125 if (err < 0) {
1126 mgmt_pending_remove(cmd);
1127 goto failed;
1128 }
1129
1130failed:
1131 hci_dev_unlock(hdev);
1132 hci_dev_put(hdev);
1133
1134 return err;
1135}
1136
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001137static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1138{
1139 struct mgmt_mode *cp = data;
1140 struct pending_cmd *cmd;
1141 struct hci_dev *hdev;
1142 uint8_t val;
1143 int err;
1144
1145 BT_DBG("request for hci%u", index);
1146
1147 if (len != sizeof(*cp))
1148 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1149 MGMT_STATUS_INVALID_PARAMS);
1150
1151 hdev = hci_dev_get(index);
1152 if (!hdev)
1153 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1154 MGMT_STATUS_INVALID_PARAMS);
1155
1156 hci_dev_lock(hdev);
1157
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001158 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1159 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1160 MGMT_STATUS_NOT_SUPPORTED);
1161 goto failed;
1162 }
1163
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001164 val = !!cp->val;
1165
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001166 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001167 bool changed = false;
1168
1169 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1170 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1171 changed = true;
1172 }
1173
1174 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1175 if (err < 0)
1176 goto failed;
1177
1178 if (changed)
1179 err = new_settings(hdev, sk);
1180
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001181 goto failed;
1182 }
1183
1184 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1185 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1186 goto failed;
1187 }
1188
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001189 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1190 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1191 goto failed;
1192 }
1193
1194 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1195 if (!cmd) {
1196 err = -ENOMEM;
1197 goto failed;
1198 }
1199
1200 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1201 if (err < 0) {
1202 mgmt_pending_remove(cmd);
1203 goto failed;
1204 }
1205
1206failed:
1207 hci_dev_unlock(hdev);
1208 hci_dev_put(hdev);
1209
1210 return err;
1211}
1212
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001213static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1214{
1215 struct mgmt_mode *cp = data;
1216 struct hci_dev *hdev;
1217 int err;
1218
1219 BT_DBG("request for hci%u", index);
1220
1221 if (len != sizeof(*cp))
1222 return cmd_status(sk, index, MGMT_OP_SET_HS,
1223 MGMT_STATUS_INVALID_PARAMS);
1224
1225 hdev = hci_dev_get(index);
1226 if (!hdev)
1227 return cmd_status(sk, index, MGMT_OP_SET_HS,
1228 MGMT_STATUS_INVALID_PARAMS);
1229
1230 if (!enable_hs) {
1231 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1232 MGMT_STATUS_NOT_SUPPORTED);
1233 goto failed;
1234 }
1235
1236 if (cp->val)
1237 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1238 else
1239 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1240
1241 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1242
1243failed:
1244 hci_dev_put(hdev);
1245 return err;
1246}
1247
Johan Hedberg06199cf2012-02-22 16:37:11 +02001248static int set_le(struct sock *sk, u16 index, void *data, u16 len)
1249{
1250 struct mgmt_mode *cp = data;
1251 struct hci_cp_write_le_host_supported hci_cp;
1252 struct pending_cmd *cmd;
1253 struct hci_dev *hdev;
1254 int err;
1255 u8 val;
1256
1257 BT_DBG("request for hci%u", index);
1258
1259 if (len != sizeof(*cp))
1260 return cmd_status(sk, index, MGMT_OP_SET_LE,
1261 MGMT_STATUS_INVALID_PARAMS);
1262
1263 hdev = hci_dev_get(index);
1264 if (!hdev)
1265 return cmd_status(sk, index, MGMT_OP_SET_LE,
1266 MGMT_STATUS_INVALID_PARAMS);
1267
1268 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
1269 err = cmd_status(sk, index, MGMT_OP_SET_LE,
1270 MGMT_STATUS_NOT_SUPPORTED);
1271 goto failed;
1272 }
1273
1274 val = !!cp->val;
1275
1276 if (!hdev_is_powered(hdev)) {
1277 bool changed = false;
1278
1279 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1280 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1281 changed = true;
1282 }
1283
1284 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1285 if (err < 0)
1286 goto failed;
1287
1288 if (changed)
1289 err = new_settings(hdev, sk);
1290
1291 goto failed;
1292 }
1293
1294 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
1295 err = cmd_status(sk, index, MGMT_OP_SET_LE, MGMT_STATUS_BUSY);
1296 goto failed;
1297 }
1298
1299 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1300 if (!cmd) {
1301 err = -ENOMEM;
1302 goto failed;
1303 }
1304
1305 memset(&hci_cp, 0, sizeof(hci_cp));
1306
1307 if (val) {
1308 hci_cp.le = val;
1309 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1310 }
1311
1312 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
1313 sizeof(hci_cp), &hci_cp);
1314 if (err < 0) {
1315 mgmt_pending_remove(cmd);
1316 goto failed;
1317 }
1318
1319failed:
1320 hci_dev_put(hdev);
1321 return err;
1322}
1323
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001324static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001326 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001327 struct hci_dev *hdev;
1328 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001329 int err;
1330
Szymon Janc4e51eae2011-02-25 19:05:48 +01001331 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001333 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001334 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1335 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001336
Szymon Janc4e51eae2011-02-25 19:05:48 +01001337 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001339 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1340 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001342 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001343
1344 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1345 if (!uuid) {
1346 err = -ENOMEM;
1347 goto failed;
1348 }
1349
1350 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001351 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352
1353 list_add(&uuid->list, &hdev->uuids);
1354
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001355 err = update_class(hdev);
1356 if (err < 0)
1357 goto failed;
1358
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001359 err = update_eir(hdev);
1360 if (err < 0)
1361 goto failed;
1362
Johan Hedbergaee9b212012-02-18 15:07:59 +02001363 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001364
1365failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001366 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001367 hci_dev_put(hdev);
1368
1369 return err;
1370}
1371
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001372static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001373{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001374 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001375 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001376 struct hci_dev *hdev;
1377 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 +02001378 int err, found;
1379
Szymon Janc4e51eae2011-02-25 19:05:48 +01001380 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001381
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001382 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001383 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1384 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001385
Szymon Janc4e51eae2011-02-25 19:05:48 +01001386 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001387 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001388 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1389 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001390
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001391 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001392
1393 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1394 err = hci_uuids_clear(hdev);
1395 goto unlock;
1396 }
1397
1398 found = 0;
1399
1400 list_for_each_safe(p, n, &hdev->uuids) {
1401 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1402
1403 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1404 continue;
1405
1406 list_del(&match->list);
1407 found++;
1408 }
1409
1410 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001411 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1412 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001413 goto unlock;
1414 }
1415
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001416 err = update_class(hdev);
1417 if (err < 0)
1418 goto unlock;
1419
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001420 err = update_eir(hdev);
1421 if (err < 0)
1422 goto unlock;
1423
Johan Hedbergaee9b212012-02-18 15:07:59 +02001424 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001425
1426unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001427 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001428 hci_dev_put(hdev);
1429
1430 return err;
1431}
1432
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001433static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001434{
1435 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001436 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001437 int err;
1438
Szymon Janc4e51eae2011-02-25 19:05:48 +01001439 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001440
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001441 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001442 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1443 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001444
Szymon Janc4e51eae2011-02-25 19:05:48 +01001445 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001446 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001447 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1448 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001449
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001450 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001451
Johan Hedbergb5235a62012-02-21 14:32:24 +02001452 if (!hdev_is_powered(hdev)) {
1453 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1454 MGMT_STATUS_NOT_POWERED);
1455 goto unlock;
1456 }
1457
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001458 hdev->major_class = cp->major;
1459 hdev->minor_class = cp->minor;
1460
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001461 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001462 hci_dev_unlock(hdev);
1463 cancel_delayed_work_sync(&hdev->service_cache);
1464 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001465 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001466 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001467
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001468 err = update_class(hdev);
1469
1470 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001471 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1472 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001473
Johan Hedbergb5235a62012-02-21 14:32:24 +02001474unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001475 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001476 hci_dev_put(hdev);
1477
1478 return err;
1479}
1480
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001481static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001482{
1483 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001484 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001485 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001486 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001487
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001488 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001489 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1490 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001491
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001492 key_count = get_unaligned_le16(&cp->key_count);
1493
Johan Hedberg86742e12011-11-07 23:13:38 +02001494 expected_len = sizeof(*cp) + key_count *
1495 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001496 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001497 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001498 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001499 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1500 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001501 }
1502
Szymon Janc4e51eae2011-02-25 19:05:48 +01001503 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001504 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001505 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1506 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001507
Szymon Janc4e51eae2011-02-25 19:05:48 +01001508 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001509 key_count);
1510
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001511 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001512
1513 hci_link_keys_clear(hdev);
1514
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001515 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001516
1517 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001518 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001519 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001520 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001521
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001522 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001523 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001524
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001525 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1526 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001527 }
1528
Johan Hedbergaee9b212012-02-18 15:07:59 +02001529 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001530
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001531 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001532 hci_dev_put(hdev);
1533
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001534 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001535}
1536
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001537static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1538 u8 addr_type, struct sock *skip_sk)
1539{
1540 struct mgmt_ev_device_unpaired ev;
1541
1542 bacpy(&ev.addr.bdaddr, bdaddr);
1543 ev.addr.type = addr_type;
1544
1545 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1546 skip_sk);
1547}
1548
Johan Hedberg124f6e32012-02-09 13:50:12 +02001549static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001550{
1551 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001552 struct mgmt_cp_unpair_device *cp = data;
1553 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001554 struct hci_cp_disconnect dc;
1555 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001556 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001557 u8 status = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001558 int err;
1559
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001560 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001561 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001562 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001563
Szymon Janc4e51eae2011-02-25 19:05:48 +01001564 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001565 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001566 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001567 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001568
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001569 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001570
Johan Hedberga8a1d192011-11-10 15:54:38 +02001571 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001572 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1573 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001574
Johan Hedberg124f6e32012-02-09 13:50:12 +02001575 if (cp->addr.type == MGMT_ADDR_BREDR)
1576 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1577 else
1578 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001579
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001580 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001581 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001582 goto unlock;
1583 }
1584
Johan Hedberga8a1d192011-11-10 15:54:38 +02001585 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001586 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1587 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001588 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001589 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001590 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001591
Johan Hedberg124f6e32012-02-09 13:50:12 +02001592 if (cp->addr.type == MGMT_ADDR_BREDR)
1593 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1594 &cp->addr.bdaddr);
1595 else
1596 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1597 &cp->addr.bdaddr);
1598
Johan Hedberga8a1d192011-11-10 15:54:38 +02001599 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001600 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1601 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001602 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001603 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001604 }
1605
Johan Hedberg124f6e32012-02-09 13:50:12 +02001606 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1607 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001608 if (!cmd) {
1609 err = -ENOMEM;
1610 goto unlock;
1611 }
1612
1613 put_unaligned_le16(conn->handle, &dc.handle);
1614 dc.reason = 0x13; /* Remote User Terminated Connection */
1615 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1616 if (err < 0)
1617 mgmt_pending_remove(cmd);
1618
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001619unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001620 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001621 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1622 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001623 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001624 hci_dev_put(hdev);
1625
1626 return err;
1627}
1628
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001629static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001630{
1631 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001632 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001633 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001634 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001635 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001636 int err;
1637
1638 BT_DBG("");
1639
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001640 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001641 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1642 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001643
Szymon Janc4e51eae2011-02-25 19:05:48 +01001644 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001645 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001646 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1647 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001648
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001649 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001650
1651 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001652 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1653 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001654 goto failed;
1655 }
1656
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001657 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001658 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1659 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001660 goto failed;
1661 }
1662
Johan Hedberg88c3df12012-02-09 14:27:38 +02001663 if (cp->addr.type == MGMT_ADDR_BREDR)
1664 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1665 else
1666 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001667
Johan Hedberg8962ee72011-01-20 12:40:27 +02001668 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001669 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1670 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001671 goto failed;
1672 }
1673
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001674 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001675 if (!cmd) {
1676 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001677 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001678 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001679
1680 put_unaligned_le16(conn->handle, &dc.handle);
1681 dc.reason = 0x13; /* Remote User Terminated Connection */
1682
1683 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1684 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001685 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001686
1687failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001688 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001689 hci_dev_put(hdev);
1690
1691 return err;
1692}
1693
Johan Hedberg48264f02011-11-09 13:58:58 +02001694static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001695{
1696 switch (link_type) {
1697 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001698 switch (addr_type) {
1699 case ADDR_LE_DEV_PUBLIC:
1700 return MGMT_ADDR_LE_PUBLIC;
1701 case ADDR_LE_DEV_RANDOM:
1702 return MGMT_ADDR_LE_RANDOM;
1703 default:
1704 return MGMT_ADDR_INVALID;
1705 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001706 case ACL_LINK:
1707 return MGMT_ADDR_BREDR;
1708 default:
1709 return MGMT_ADDR_INVALID;
1710 }
1711}
1712
Szymon Janc8ce62842011-03-01 16:55:32 +01001713static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001714{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001715 struct mgmt_rp_get_connections *rp;
1716 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001717 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001718 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001719 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001720 int i, err;
1721
1722 BT_DBG("");
1723
Szymon Janc4e51eae2011-02-25 19:05:48 +01001724 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001725 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001726 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1727 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001728
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001729 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001730
1731 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001732 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1733 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1734 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001735 }
1736
Johan Hedberg4c659c32011-11-07 23:13:39 +02001737 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001738 rp = kmalloc(rp_len, GFP_ATOMIC);
1739 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001740 err = -ENOMEM;
1741 goto unlock;
1742 }
1743
Johan Hedberg2784eb42011-01-21 13:56:35 +02001744 put_unaligned_le16(count, &rp->conn_count);
1745
Johan Hedberg2784eb42011-01-21 13:56:35 +02001746 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001747 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001748 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1749 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001750 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001751 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001752 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1753 continue;
1754 i++;
1755 }
1756
1757 /* Recalculate length in case of filtered SCO connections, etc */
1758 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001759
Johan Hedbergaee9b212012-02-18 15:07:59 +02001760 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001761
1762unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001763 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001764 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001765 hci_dev_put(hdev);
1766 return err;
1767}
1768
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001769static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1770 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1771{
1772 struct pending_cmd *cmd;
1773 int err;
1774
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001775 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001776 sizeof(*cp));
1777 if (!cmd)
1778 return -ENOMEM;
1779
Johan Hedbergd8457692012-02-17 14:24:57 +02001780 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1781 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001782 if (err < 0)
1783 mgmt_pending_remove(cmd);
1784
1785 return err;
1786}
1787
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001788static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789{
1790 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001791 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001792 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001793 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001794 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001795 int err;
1796
1797 BT_DBG("");
1798
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001799 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001800 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1801 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001802
Szymon Janc4e51eae2011-02-25 19:05:48 +01001803 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001804 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001805 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1806 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001807
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001808 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001809
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001810 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001811 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1812 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001813 goto failed;
1814 }
1815
Johan Hedbergd8457692012-02-17 14:24:57 +02001816 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001817 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001818 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1819 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001820 goto failed;
1821 }
1822
1823 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001824 struct mgmt_cp_pin_code_neg_reply ncp;
1825
1826 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001827
1828 BT_ERR("PIN code is not 16 bytes long");
1829
1830 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1831 if (err >= 0)
1832 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001833 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001834
1835 goto failed;
1836 }
1837
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001838 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1839 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001840 if (!cmd) {
1841 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001842 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001843 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001844
Johan Hedbergd8457692012-02-17 14:24:57 +02001845 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001846 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001847 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001848
1849 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1850 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001851 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001852
1853failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001854 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001855 hci_dev_put(hdev);
1856
1857 return err;
1858}
1859
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001860static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001861{
1862 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001863 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001864 int err;
1865
1866 BT_DBG("");
1867
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001868 if (len != sizeof(*cp))
1869 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001870 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001871
Szymon Janc4e51eae2011-02-25 19:05:48 +01001872 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001873 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001875 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001876
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001877 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001878
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001879 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001881 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001882 goto failed;
1883 }
1884
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001885 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001886
1887failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001888 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001889 hci_dev_put(hdev);
1890
1891 return err;
1892}
1893
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001894static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001895{
1896 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001897 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001898
1899 BT_DBG("");
1900
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001901 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001902 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1903 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001904
Szymon Janc4e51eae2011-02-25 19:05:48 +01001905 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001906 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001907 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1908 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001909
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001910 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001911
1912 hdev->io_capability = cp->io_capability;
1913
1914 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001915 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001916
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001917 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001918 hci_dev_put(hdev);
1919
Johan Hedbergaee9b212012-02-18 15:07:59 +02001920 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001921}
1922
Johan Hedberge9a416b2011-02-19 12:05:56 -03001923static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1924{
1925 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001926 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001927
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001928 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001929 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1930 continue;
1931
Johan Hedberge9a416b2011-02-19 12:05:56 -03001932 if (cmd->user_data != conn)
1933 continue;
1934
1935 return cmd;
1936 }
1937
1938 return NULL;
1939}
1940
1941static void pairing_complete(struct pending_cmd *cmd, u8 status)
1942{
1943 struct mgmt_rp_pair_device rp;
1944 struct hci_conn *conn = cmd->user_data;
1945
Johan Hedbergba4e5642011-11-11 00:07:34 +02001946 bacpy(&rp.addr.bdaddr, &conn->dst);
1947 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001948
Johan Hedbergaee9b212012-02-18 15:07:59 +02001949 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1950 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951
1952 /* So we don't get further callbacks for this connection */
1953 conn->connect_cfm_cb = NULL;
1954 conn->security_cfm_cb = NULL;
1955 conn->disconn_cfm_cb = NULL;
1956
1957 hci_conn_put(conn);
1958
Johan Hedberga664b5b2011-02-19 12:06:02 -03001959 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001960}
1961
1962static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1963{
1964 struct pending_cmd *cmd;
1965
1966 BT_DBG("status %u", status);
1967
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001968 cmd = find_pairing(conn);
1969 if (!cmd)
1970 BT_DBG("Unable to find a pending command");
1971 else
Johan Hedberge2113262012-02-18 15:20:03 +02001972 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001973}
1974
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001975static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001976{
1977 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001978 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001979 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001980 struct pending_cmd *cmd;
1981 u8 sec_level, auth_type;
1982 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001983 int err;
1984
1985 BT_DBG("");
1986
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001987 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001988 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1989 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001990
Szymon Janc4e51eae2011-02-25 19:05:48 +01001991 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001992 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001993 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1994 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001995
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001996 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001997
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001998 sec_level = BT_SECURITY_MEDIUM;
1999 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002000 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002001 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002002 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002003
Johan Hedbergba4e5642011-11-11 00:07:34 +02002004 if (cp->addr.type == MGMT_ADDR_BREDR)
2005 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002006 auth_type);
2007 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02002008 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002009 auth_type);
2010
Johan Hedberg1425acb2011-11-11 00:07:35 +02002011 memset(&rp, 0, sizeof(rp));
2012 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2013 rp.addr.type = cp->addr.type;
2014
Ville Tervo30e76272011-02-22 16:10:53 -03002015 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02002016 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2017 MGMT_STATUS_CONNECT_FAILED,
2018 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002019 goto unlock;
2020 }
2021
2022 if (conn->connect_cfm_cb) {
2023 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02002024 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
2025 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002026 goto unlock;
2027 }
2028
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002029 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002030 if (!cmd) {
2031 err = -ENOMEM;
2032 hci_conn_put(conn);
2033 goto unlock;
2034 }
2035
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002036 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02002037 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002038 conn->connect_cfm_cb = pairing_complete_cb;
2039
Johan Hedberge9a416b2011-02-19 12:05:56 -03002040 conn->security_cfm_cb = pairing_complete_cb;
2041 conn->disconn_cfm_cb = pairing_complete_cb;
2042 conn->io_capability = cp->io_cap;
2043 cmd->user_data = conn;
2044
2045 if (conn->state == BT_CONNECTED &&
2046 hci_conn_security(conn, sec_level, auth_type))
2047 pairing_complete(cmd, 0);
2048
2049 err = 0;
2050
2051unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002052 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002053 hci_dev_put(hdev);
2054
2055 return err;
2056}
2057
Johan Hedberg28424702012-02-02 04:02:29 +02002058static int cancel_pair_device(struct sock *sk, u16 index,
2059 unsigned char *data, u16 len)
2060{
2061 struct mgmt_addr_info *addr = (void *) data;
2062 struct hci_dev *hdev;
2063 struct pending_cmd *cmd;
2064 struct hci_conn *conn;
2065 int err;
2066
2067 BT_DBG("");
2068
2069 if (len != sizeof(*addr))
2070 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2071 MGMT_STATUS_INVALID_PARAMS);
2072
2073 hdev = hci_dev_get(index);
2074 if (!hdev)
2075 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2076 MGMT_STATUS_INVALID_PARAMS);
2077
2078 hci_dev_lock(hdev);
2079
2080 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2081 if (!cmd) {
2082 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2083 MGMT_STATUS_INVALID_PARAMS);
2084 goto unlock;
2085 }
2086
2087 conn = cmd->user_data;
2088
2089 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
2090 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
2091 MGMT_STATUS_INVALID_PARAMS);
2092 goto unlock;
2093 }
2094
2095 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2096
Johan Hedbergaee9b212012-02-18 15:07:59 +02002097 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002098 sizeof(*addr));
2099unlock:
2100 hci_dev_unlock(hdev);
2101 hci_dev_put(hdev);
2102
2103 return err;
2104}
2105
Brian Gix0df4c182011-11-16 13:53:13 -08002106static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002107 u8 type, u16 mgmt_op, u16 hci_op,
2108 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002109{
Johan Hedberga5c29682011-02-19 12:05:57 -03002110 struct pending_cmd *cmd;
2111 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002112 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002113 int err;
2114
Szymon Janc4e51eae2011-02-25 19:05:48 +01002115 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002116 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002117 return cmd_status(sk, index, mgmt_op,
2118 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002120 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002121
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002122 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002123 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2124 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002125 }
2126
Johan Hedberg272d90d2012-02-09 15:26:12 +02002127 if (type == MGMT_ADDR_BREDR)
2128 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2129 else
Brian Gix47c15e22011-11-16 13:53:14 -08002130 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002131
Johan Hedberg272d90d2012-02-09 15:26:12 +02002132 if (!conn) {
2133 err = cmd_status(sk, index, mgmt_op,
2134 MGMT_STATUS_NOT_CONNECTED);
2135 goto done;
2136 }
2137
2138 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002139 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002140 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002141
Brian Gix5fe57d92011-12-21 16:12:13 -08002142 if (!err)
2143 err = cmd_status(sk, index, mgmt_op,
2144 MGMT_STATUS_SUCCESS);
2145 else
2146 err = cmd_status(sk, index, mgmt_op,
2147 MGMT_STATUS_FAILED);
2148
Brian Gix47c15e22011-11-16 13:53:14 -08002149 goto done;
2150 }
2151
Brian Gix0df4c182011-11-16 13:53:13 -08002152 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002153 if (!cmd) {
2154 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002155 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002156 }
2157
Brian Gix0df4c182011-11-16 13:53:13 -08002158 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002159 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2160 struct hci_cp_user_passkey_reply cp;
2161
2162 bacpy(&cp.bdaddr, bdaddr);
2163 cp.passkey = passkey;
2164 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2165 } else
2166 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2167
Johan Hedberga664b5b2011-02-19 12:06:02 -03002168 if (err < 0)
2169 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002170
Brian Gix0df4c182011-11-16 13:53:13 -08002171done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002172 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002173 hci_dev_put(hdev);
2174
2175 return err;
2176}
2177
Brian Gix0df4c182011-11-16 13:53:13 -08002178static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2179{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002180 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002181
2182 BT_DBG("");
2183
2184 if (len != sizeof(*cp))
2185 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2186 MGMT_STATUS_INVALID_PARAMS);
2187
Johan Hedberg272d90d2012-02-09 15:26:12 +02002188 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2189 MGMT_OP_USER_CONFIRM_REPLY,
2190 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002191}
2192
2193static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2194 u16 len)
2195{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002196 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002197
2198 BT_DBG("");
2199
2200 if (len != sizeof(*cp))
2201 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2202 MGMT_STATUS_INVALID_PARAMS);
2203
Johan Hedberg272d90d2012-02-09 15:26:12 +02002204 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2205 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2206 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002207}
2208
Brian Gix604086b2011-11-23 08:28:33 -08002209static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2210{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002211 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002212
2213 BT_DBG("");
2214
2215 if (len != sizeof(*cp))
2216 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2217 EINVAL);
2218
Johan Hedberg272d90d2012-02-09 15:26:12 +02002219 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2220 MGMT_OP_USER_PASSKEY_REPLY,
2221 HCI_OP_USER_PASSKEY_REPLY,
2222 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002223}
2224
2225static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2226 u16 len)
2227{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002228 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002229
2230 BT_DBG("");
2231
2232 if (len != sizeof(*cp))
2233 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2234 EINVAL);
2235
Johan Hedberg272d90d2012-02-09 15:26:12 +02002236 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2237 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2238 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002239}
2240
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002241static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002242 u16 len)
2243{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002244 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002245 struct hci_cp_write_local_name hci_cp;
2246 struct hci_dev *hdev;
2247 struct pending_cmd *cmd;
2248 int err;
2249
2250 BT_DBG("");
2251
2252 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002253 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2254 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002255
2256 hdev = hci_dev_get(index);
2257 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002258 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2259 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002260
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002261 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002262
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002263 memcpy(hdev->short_name, mgmt_cp->short_name,
2264 sizeof(hdev->short_name));
2265
Johan Hedbergb5235a62012-02-21 14:32:24 +02002266 if (!hdev_is_powered(hdev)) {
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002267 memcpy(hdev->dev_name, mgmt_cp->name, sizeof(hdev->dev_name));
2268
2269 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2270 data, len);
2271 if (err < 0)
2272 goto failed;
2273
2274 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
2275 sk);
2276
Johan Hedbergb5235a62012-02-21 14:32:24 +02002277 goto failed;
2278 }
2279
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002280 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002281 if (!cmd) {
2282 err = -ENOMEM;
2283 goto failed;
2284 }
2285
2286 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2287 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2288 &hci_cp);
2289 if (err < 0)
2290 mgmt_pending_remove(cmd);
2291
2292failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002293 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002294 hci_dev_put(hdev);
2295
2296 return err;
2297}
2298
Szymon Jancc35938b2011-03-22 13:12:21 +01002299static int read_local_oob_data(struct sock *sk, u16 index)
2300{
2301 struct hci_dev *hdev;
2302 struct pending_cmd *cmd;
2303 int err;
2304
2305 BT_DBG("hci%u", index);
2306
2307 hdev = hci_dev_get(index);
2308 if (!hdev)
2309 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002310 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002311
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002312 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002313
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002314 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002315 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002316 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002317 goto unlock;
2318 }
2319
2320 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2321 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002322 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002323 goto unlock;
2324 }
2325
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002326 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002327 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2328 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002329 goto unlock;
2330 }
2331
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002332 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002333 if (!cmd) {
2334 err = -ENOMEM;
2335 goto unlock;
2336 }
2337
2338 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2339 if (err < 0)
2340 mgmt_pending_remove(cmd);
2341
2342unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002343 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002344 hci_dev_put(hdev);
2345
2346 return err;
2347}
2348
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002349static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2350 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002351{
2352 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002353 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002354 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002355 int err;
2356
2357 BT_DBG("hci%u ", index);
2358
2359 if (len != sizeof(*cp))
2360 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002361 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002362
2363 hdev = hci_dev_get(index);
2364 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002365 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2366 MGMT_STATUS_INVALID_PARAMS,
2367 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002368
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002370
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002371 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002372 cp->randomizer);
2373 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002374 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002375 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002376 status = 0;
2377
2378 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2379 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002380
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002381 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002382 hci_dev_put(hdev);
2383
2384 return err;
2385}
2386
2387static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002388 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002389{
2390 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002391 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002392 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002393 int err;
2394
2395 BT_DBG("hci%u ", index);
2396
2397 if (len != sizeof(*cp))
2398 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002399 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002400
2401 hdev = hci_dev_get(index);
2402 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002403 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2404 MGMT_STATUS_INVALID_PARAMS,
2405 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002406
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002407 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002408
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002409 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002410 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002411 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002412 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002413 status = 0;
2414
2415 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2416 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002417
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002418 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002419 hci_dev_put(hdev);
2420
2421 return err;
2422}
2423
Andre Guedes5e0452c2012-02-17 20:39:38 -03002424static int discovery(struct hci_dev *hdev)
2425{
2426 int err;
2427
2428 if (lmp_host_le_capable(hdev)) {
2429 if (lmp_bredr_capable(hdev)) {
2430 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2431 LE_SCAN_INT, LE_SCAN_WIN,
2432 LE_SCAN_TIMEOUT_BREDR_LE);
2433 } else {
2434 hdev->discovery.type = DISCOV_TYPE_LE;
2435 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2436 LE_SCAN_INT, LE_SCAN_WIN,
2437 LE_SCAN_TIMEOUT_LE_ONLY);
2438 }
2439 } else {
2440 hdev->discovery.type = DISCOV_TYPE_BREDR;
2441 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2442 }
2443
2444 return err;
2445}
2446
2447int mgmt_interleaved_discovery(struct hci_dev *hdev)
2448{
2449 int err;
2450
2451 BT_DBG("%s", hdev->name);
2452
2453 hci_dev_lock(hdev);
2454
2455 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2456 if (err < 0)
2457 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2458
2459 hci_dev_unlock(hdev);
2460
2461 return err;
2462}
2463
Johan Hedberg450dfda2011-11-12 11:58:22 +02002464static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002465 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002466{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002467 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002468 struct pending_cmd *cmd;
2469 struct hci_dev *hdev;
2470 int err;
2471
2472 BT_DBG("hci%u", index);
2473
Johan Hedberg450dfda2011-11-12 11:58:22 +02002474 if (len != sizeof(*cp))
2475 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2476 MGMT_STATUS_INVALID_PARAMS);
2477
Johan Hedberg14a53662011-04-27 10:29:56 -04002478 hdev = hci_dev_get(index);
2479 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002480 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2481 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002482
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002483 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002484
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002485 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002486 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2487 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002488 goto failed;
2489 }
2490
Johan Hedbergff9ef572012-01-04 14:23:45 +02002491 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2492 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2493 MGMT_STATUS_BUSY);
2494 goto failed;
2495 }
2496
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002497 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002498 if (!cmd) {
2499 err = -ENOMEM;
2500 goto failed;
2501 }
2502
Andre Guedes4aab14e2012-02-17 20:39:36 -03002503 hdev->discovery.type = cp->type;
2504
2505 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002506 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002507 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002508 break;
2509
2510 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002511 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2512 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002513 break;
2514
Andre Guedes5e0452c2012-02-17 20:39:38 -03002515 case DISCOV_TYPE_INTERLEAVED:
2516 err = discovery(hdev);
2517 break;
2518
Andre Guedesf39799f2012-02-17 20:39:35 -03002519 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002520 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002521 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002522
Johan Hedberg14a53662011-04-27 10:29:56 -04002523 if (err < 0)
2524 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002525 else
2526 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002527
2528failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002529 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002530 hci_dev_put(hdev);
2531
2532 return err;
2533}
2534
Johan Hedbergd9306502012-02-20 23:25:18 +02002535static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002536{
Johan Hedbergd9306502012-02-20 23:25:18 +02002537 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002538 struct hci_dev *hdev;
2539 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002540 struct hci_cp_remote_name_req_cancel cp;
2541 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002542 int err;
2543
2544 BT_DBG("hci%u", index);
2545
Johan Hedbergd9306502012-02-20 23:25:18 +02002546 if (len != sizeof(*mgmt_cp))
2547 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2548 MGMT_STATUS_INVALID_PARAMS);
2549
Johan Hedberg14a53662011-04-27 10:29:56 -04002550 hdev = hci_dev_get(index);
2551 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002552 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2553 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002554
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002555 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002556
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002557 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002558 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2559 MGMT_STATUS_REJECTED,
2560 &mgmt_cp->type, sizeof(mgmt_cp->type));
2561 goto unlock;
2562 }
2563
2564 if (hdev->discovery.type != mgmt_cp->type) {
2565 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2566 MGMT_STATUS_INVALID_PARAMS,
2567 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002568 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002569 }
2570
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002571 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002572 if (!cmd) {
2573 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002574 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002575 }
2576
Andre Guedes343f9352012-02-17 20:39:37 -03002577 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002578 err = hci_cancel_inquiry(hdev);
2579 if (err < 0)
2580 mgmt_pending_remove(cmd);
2581 else
2582 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2583 goto unlock;
2584 }
2585
2586 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2587 if (!e) {
2588 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002589 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002590 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002591 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2592 goto unlock;
2593 }
2594
2595 bacpy(&cp.bdaddr, &e->data.bdaddr);
2596 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2597 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002598 if (err < 0)
2599 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002600 else
2601 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002602
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002603unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002604 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002605 hci_dev_put(hdev);
2606
2607 return err;
2608}
2609
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002610static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002611{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002612 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002613 struct inquiry_entry *e;
2614 struct hci_dev *hdev;
2615 int err;
2616
2617 BT_DBG("hci%u", index);
2618
2619 if (len != sizeof(*cp))
2620 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2621 MGMT_STATUS_INVALID_PARAMS);
2622
2623 hdev = hci_dev_get(index);
2624 if (!hdev)
2625 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2626 MGMT_STATUS_INVALID_PARAMS);
2627
2628 hci_dev_lock(hdev);
2629
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002630 if (!hci_discovery_active(hdev)) {
2631 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2632 MGMT_STATUS_FAILED);
2633 goto failed;
2634 }
2635
Johan Hedberga198e7b2012-02-17 14:27:06 +02002636 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002637 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002638 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002639 MGMT_STATUS_INVALID_PARAMS);
2640 goto failed;
2641 }
2642
2643 if (cp->name_known) {
2644 e->name_state = NAME_KNOWN;
2645 list_del(&e->list);
2646 } else {
2647 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002648 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002649 }
2650
2651 err = 0;
2652
2653failed:
2654 hci_dev_unlock(hdev);
2655
2656 return err;
2657}
2658
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002659static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002660{
2661 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002662 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002663 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002664 int err;
2665
2666 BT_DBG("hci%u", index);
2667
Antti Julku7fbec222011-06-15 12:01:15 +03002668 if (len != sizeof(*cp))
2669 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002670 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002671
2672 hdev = hci_dev_get(index);
2673 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002674 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2675 MGMT_STATUS_INVALID_PARAMS,
2676 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002678 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002679
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002680 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002681 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002682 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002683 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002684 status = 0;
2685
2686 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2687 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002688
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002689 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002690 hci_dev_put(hdev);
2691
2692 return err;
2693}
2694
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002695static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002696{
2697 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002698 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002699 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002700 int err;
2701
2702 BT_DBG("hci%u", index);
2703
Antti Julku7fbec222011-06-15 12:01:15 +03002704 if (len != sizeof(*cp))
2705 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002706 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002707
2708 hdev = hci_dev_get(index);
2709 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002710 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2711 MGMT_STATUS_INVALID_PARAMS,
2712 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002713
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002714 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002715
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002716 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002717 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002718 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002719 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002720 status = 0;
2721
2722 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2723 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002724
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002725 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002726 hci_dev_put(hdev);
2727
2728 return err;
2729}
2730
Antti Julkuf6422ec2011-06-22 13:11:56 +03002731static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002732 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002733{
2734 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002735 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002736 struct hci_cp_write_page_scan_activity acp;
2737 u8 type;
2738 int err;
2739
2740 BT_DBG("hci%u", index);
2741
2742 if (len != sizeof(*cp))
2743 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002744 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002745
2746 hdev = hci_dev_get(index);
2747 if (!hdev)
2748 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002749 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002750 if (!hdev_is_powered(hdev))
2751 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2752 MGMT_STATUS_NOT_POWERED);
2753
2754 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2755 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2756 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002757
2758 hci_dev_lock(hdev);
2759
Johan Hedbergf7c68692011-12-15 00:47:36 +02002760 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002761 type = PAGE_SCAN_TYPE_INTERLACED;
2762 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2763 } else {
2764 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2765 acp.interval = 0x0800; /* default 1.28 sec page scan */
2766 }
2767
2768 acp.window = 0x0012; /* default 11.25 msec page scan window */
2769
2770 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2771 sizeof(acp), &acp);
2772 if (err < 0) {
2773 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002774 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002775 goto done;
2776 }
2777
2778 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2779 if (err < 0) {
2780 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002781 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002782 goto done;
2783 }
2784
Johan Hedbergaee9b212012-02-18 15:07:59 +02002785 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2786 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002787done:
2788 hci_dev_unlock(hdev);
2789 hci_dev_put(hdev);
2790
2791 return err;
2792}
2793
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002794static int load_long_term_keys(struct sock *sk, u16 index,
2795 void *cp_data, u16 len)
2796{
2797 struct hci_dev *hdev;
2798 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2799 u16 key_count, expected_len;
2800 int i;
2801
2802 if (len < sizeof(*cp))
2803 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2804 EINVAL);
2805
2806 key_count = get_unaligned_le16(&cp->key_count);
2807
2808 expected_len = sizeof(*cp) + key_count *
2809 sizeof(struct mgmt_ltk_info);
2810 if (expected_len != len) {
2811 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2812 len, expected_len);
2813 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2814 EINVAL);
2815 }
2816
2817 hdev = hci_dev_get(index);
2818 if (!hdev)
2819 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2820 ENODEV);
2821
2822 BT_DBG("hci%u key_count %u", index, key_count);
2823
2824 hci_dev_lock(hdev);
2825
2826 hci_smp_ltks_clear(hdev);
2827
2828 for (i = 0; i < key_count; i++) {
2829 struct mgmt_ltk_info *key = &cp->keys[i];
2830 u8 type;
2831
2832 if (key->master)
2833 type = HCI_SMP_LTK;
2834 else
2835 type = HCI_SMP_LTK_SLAVE;
2836
2837 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2838 type, 0, key->authenticated, key->val,
2839 key->enc_size, key->ediv, key->rand);
2840 }
2841
2842 hci_dev_unlock(hdev);
2843 hci_dev_put(hdev);
2844
2845 return 0;
2846}
2847
Johan Hedberg03811012010-12-08 00:21:06 +02002848int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2849{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002850 void *buf;
2851 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002852 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002853 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002854 int err;
2855
2856 BT_DBG("got %zu bytes", msglen);
2857
2858 if (msglen < sizeof(*hdr))
2859 return -EINVAL;
2860
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002861 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002862 if (!buf)
2863 return -ENOMEM;
2864
2865 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2866 err = -EFAULT;
2867 goto done;
2868 }
2869
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002870 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002871 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002872 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002873 len = get_unaligned_le16(&hdr->len);
2874
2875 if (len != msglen - sizeof(*hdr)) {
2876 err = -EINVAL;
2877 goto done;
2878 }
2879
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002880 cp = buf + sizeof(*hdr);
2881
Johan Hedberg03811012010-12-08 00:21:06 +02002882 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002883 case MGMT_OP_READ_VERSION:
2884 err = read_version(sk);
2885 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002886 case MGMT_OP_READ_COMMANDS:
2887 err = read_commands(sk);
2888 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002889 case MGMT_OP_READ_INDEX_LIST:
2890 err = read_index_list(sk);
2891 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002892 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002893 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002894 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002895 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002896 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002897 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002898 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002899 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002900 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002901 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002902 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002903 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002904 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002905 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002906 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002907 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002908 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002909 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002910 case MGMT_OP_SET_LINK_SECURITY:
2911 err = set_link_security(sk, index, cp, len);
2912 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002913 case MGMT_OP_SET_SSP:
2914 err = set_ssp(sk, index, cp, len);
2915 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002916 case MGMT_OP_SET_HS:
2917 err = set_hs(sk, index, cp, len);
2918 break;
Johan Hedberg06199cf2012-02-22 16:37:11 +02002919 case MGMT_OP_SET_LE:
2920 err = set_le(sk, index, cp, len);
2921 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002922 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002923 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002924 break;
2925 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002926 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002927 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002928 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002929 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002930 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002931 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002932 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002933 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002934 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002935 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002936 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002937 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002938 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002939 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002940 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002941 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002942 break;
2943 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002944 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002945 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002946 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002947 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002948 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002949 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002950 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002951 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002952 case MGMT_OP_CANCEL_PAIR_DEVICE:
2953 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2954 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002955 case MGMT_OP_UNPAIR_DEVICE:
2956 err = unpair_device(sk, index, cp, len);
2957 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002958 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002959 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002960 break;
2961 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002962 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002963 break;
Brian Gix604086b2011-11-23 08:28:33 -08002964 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002965 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002966 break;
2967 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002968 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002969 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002970 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002971 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002972 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002973 case MGMT_OP_READ_LOCAL_OOB_DATA:
2974 err = read_local_oob_data(sk, index);
2975 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002976 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002977 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002978 break;
2979 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002980 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002981 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002982 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002983 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002984 break;
2985 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002986 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002987 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002988 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002989 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002990 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002991 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002992 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002993 break;
2994 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002995 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002996 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002997 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2998 err = load_long_term_keys(sk, index, cp, len);
2999 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003000 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02003001 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003002 err = cmd_status(sk, index, opcode,
3003 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003004 break;
3005 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02003006
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003007 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02003008 goto done;
3009
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003010 err = msglen;
3011
3012done:
3013 kfree(buf);
3014 return err;
3015}
3016
Johan Hedbergb24752f2011-11-03 14:40:33 +02003017static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3018{
3019 u8 *status = data;
3020
3021 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3022 mgmt_pending_remove(cmd);
3023}
3024
Johan Hedberg744cf192011-11-08 20:40:14 +02003025int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003026{
Johan Hedberg744cf192011-11-08 20:40:14 +02003027 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003028}
3029
Johan Hedberg744cf192011-11-08 20:40:14 +02003030int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02003031{
Johan Hedbergb24752f2011-11-03 14:40:33 +02003032 u8 status = ENODEV;
3033
Johan Hedberg744cf192011-11-08 20:40:14 +02003034 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003035
Johan Hedberg744cf192011-11-08 20:40:14 +02003036 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003037}
3038
3039struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02003040 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003041 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02003042};
3043
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003044static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02003045{
Johan Hedberg03811012010-12-08 00:21:06 +02003046 struct cmd_lookup *match = data;
3047
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003048 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02003049
3050 list_del(&cmd->list);
3051
3052 if (match->sk == NULL) {
3053 match->sk = cmd->sk;
3054 sock_hold(match->sk);
3055 }
3056
3057 mgmt_pending_free(cmd);
3058}
3059
Johan Hedberg744cf192011-11-08 20:40:14 +02003060int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02003061{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003062 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003063 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02003064
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003065 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3066 return 0;
3067
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003068 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02003069
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003070 if (powered) {
3071 u8 scan = 0;
3072
3073 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3074 scan |= SCAN_PAGE;
3075 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3076 scan |= SCAN_INQUIRY;
3077
3078 if (scan)
3079 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3080 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02003081 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02003082 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003083 }
3084
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003085 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003086
3087 if (match.sk)
3088 sock_put(match.sk);
3089
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003090 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003091}
3092
Johan Hedberg744cf192011-11-08 20:40:14 +02003093int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02003094{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003095 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003096 bool changed = false;
3097 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003098
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003099 if (discoverable) {
3100 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3101 changed = true;
3102 } else {
3103 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3104 changed = true;
3105 }
Johan Hedberg03811012010-12-08 00:21:06 +02003106
Johan Hedberged9b5f22012-02-21 20:47:06 +02003107 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3108 &match);
3109
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003110 if (changed)
3111 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003112
Johan Hedberg03811012010-12-08 00:21:06 +02003113 if (match.sk)
3114 sock_put(match.sk);
3115
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003116 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003117}
3118
Johan Hedberg744cf192011-11-08 20:40:14 +02003119int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003120{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003121 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003122 bool changed = false;
3123 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003124
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003125 if (connectable) {
3126 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3127 changed = true;
3128 } else {
3129 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3130 changed = true;
3131 }
Johan Hedberg03811012010-12-08 00:21:06 +02003132
Johan Hedberged9b5f22012-02-21 20:47:06 +02003133 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3134 &match);
3135
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003136 if (changed)
3137 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003138
3139 if (match.sk)
3140 sock_put(match.sk);
3141
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003142 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003143}
3144
Johan Hedberg744cf192011-11-08 20:40:14 +02003145int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003146{
Johan Hedbergca69b792011-11-11 18:10:00 +02003147 u8 mgmt_err = mgmt_status(status);
3148
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003149 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003150 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003151 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003152
3153 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003154 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003155 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003156
3157 return 0;
3158}
3159
Johan Hedberg744cf192011-11-08 20:40:14 +02003160int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3161 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003162{
Johan Hedberg86742e12011-11-07 23:13:38 +02003163 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003164
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003165 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003166
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003167 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003168 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3169 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003170 ev.key.type = key->type;
3171 memcpy(ev.key.val, key->val, 16);
3172 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003173
Johan Hedberg744cf192011-11-08 20:40:14 +02003174 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003175}
Johan Hedbergf7520542011-01-20 12:34:39 +02003176
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003177int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3178{
3179 struct mgmt_ev_new_long_term_key ev;
3180
3181 memset(&ev, 0, sizeof(ev));
3182
3183 ev.store_hint = persistent;
3184 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3185 ev.key.addr.type = key->bdaddr_type;
3186 ev.key.authenticated = key->authenticated;
3187 ev.key.enc_size = key->enc_size;
3188 ev.key.ediv = key->ediv;
3189
3190 if (key->type == HCI_SMP_LTK)
3191 ev.key.master = 1;
3192
3193 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3194 memcpy(ev.key.val, key->val, sizeof(key->val));
3195
3196 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3197 &ev, sizeof(ev), NULL);
3198}
3199
Johan Hedbergafc747a2012-01-15 18:11:07 +02003200int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003201 u8 addr_type, u8 *name, u8 name_len,
3202 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003203{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003204 char buf[512];
3205 struct mgmt_ev_device_connected *ev = (void *) buf;
3206 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003207
Johan Hedbergb644ba32012-01-17 21:48:47 +02003208 bacpy(&ev->addr.bdaddr, bdaddr);
3209 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003210
Johan Hedbergb644ba32012-01-17 21:48:47 +02003211 if (name_len > 0)
3212 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3213 name, name_len);
3214
3215 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3216 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3217 EIR_CLASS_OF_DEV, dev_class, 3);
3218
3219 put_unaligned_le16(eir_len, &ev->eir_len);
3220
3221 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3222 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003223}
3224
Johan Hedberg8962ee72011-01-20 12:40:27 +02003225static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3226{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003227 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003228 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003229 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003230
Johan Hedberg88c3df12012-02-09 14:27:38 +02003231 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3232 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003233
Johan Hedbergaee9b212012-02-18 15:07:59 +02003234 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3235 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003236
3237 *sk = cmd->sk;
3238 sock_hold(*sk);
3239
Johan Hedberga664b5b2011-02-19 12:06:02 -03003240 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003241}
3242
Johan Hedberg124f6e32012-02-09 13:50:12 +02003243static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003244{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003245 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003246 struct mgmt_cp_unpair_device *cp = cmd->param;
3247 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003248
3249 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003250 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3251 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003252
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003253 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3254
Johan Hedbergaee9b212012-02-18 15:07:59 +02003255 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003256
3257 mgmt_pending_remove(cmd);
3258}
3259
Johan Hedbergafc747a2012-01-15 18:11:07 +02003260int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3261 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003262{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003263 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003264 struct sock *sk = NULL;
3265 int err;
3266
Johan Hedberg744cf192011-11-08 20:40:14 +02003267 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003268
Johan Hedbergf7520542011-01-20 12:34:39 +02003269 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003270 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003271
Johan Hedbergafc747a2012-01-15 18:11:07 +02003272 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3273 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003274
3275 if (sk)
3276 sock_put(sk);
3277
Johan Hedberg124f6e32012-02-09 13:50:12 +02003278 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003279 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003280
Johan Hedberg8962ee72011-01-20 12:40:27 +02003281 return err;
3282}
3283
Johan Hedberg88c3df12012-02-09 14:27:38 +02003284int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3285 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003286{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003287 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003288 struct pending_cmd *cmd;
3289 int err;
3290
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003291 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003292 if (!cmd)
3293 return -ENOENT;
3294
Johan Hedberg88c3df12012-02-09 14:27:38 +02003295 bacpy(&rp.addr.bdaddr, bdaddr);
3296 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003297
Johan Hedberg88c3df12012-02-09 14:27:38 +02003298 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003299 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003300
Johan Hedberga664b5b2011-02-19 12:06:02 -03003301 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003302
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003303 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3304 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003305 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003306}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003307
Johan Hedberg48264f02011-11-09 13:58:58 +02003308int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3309 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003310{
3311 struct mgmt_ev_connect_failed ev;
3312
Johan Hedberg4c659c32011-11-07 23:13:39 +02003313 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003314 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003315 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003316
Johan Hedberg744cf192011-11-08 20:40:14 +02003317 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003318}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003319
Johan Hedberg744cf192011-11-08 20:40:14 +02003320int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003321{
3322 struct mgmt_ev_pin_code_request ev;
3323
Johan Hedbergd8457692012-02-17 14:24:57 +02003324 bacpy(&ev.addr.bdaddr, bdaddr);
3325 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003326 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003327
Johan Hedberg744cf192011-11-08 20:40:14 +02003328 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003329 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003330}
3331
Johan Hedberg744cf192011-11-08 20:40:14 +02003332int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3333 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003334{
3335 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003336 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003337 int err;
3338
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003339 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003340 if (!cmd)
3341 return -ENOENT;
3342
Johan Hedbergd8457692012-02-17 14:24:57 +02003343 bacpy(&rp.addr.bdaddr, bdaddr);
3344 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003345
Johan Hedbergaee9b212012-02-18 15:07:59 +02003346 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3347 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003348
Johan Hedberga664b5b2011-02-19 12:06:02 -03003349 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003350
3351 return err;
3352}
3353
Johan Hedberg744cf192011-11-08 20:40:14 +02003354int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3355 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003356{
3357 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003358 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003359 int err;
3360
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003361 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003362 if (!cmd)
3363 return -ENOENT;
3364
Johan Hedbergd8457692012-02-17 14:24:57 +02003365 bacpy(&rp.addr.bdaddr, bdaddr);
3366 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003367
Johan Hedbergaee9b212012-02-18 15:07:59 +02003368 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3369 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003370
Johan Hedberga664b5b2011-02-19 12:06:02 -03003371 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003372
3373 return err;
3374}
Johan Hedberga5c29682011-02-19 12:05:57 -03003375
Johan Hedberg744cf192011-11-08 20:40:14 +02003376int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003377 u8 link_type, u8 addr_type, __le32 value,
3378 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003379{
3380 struct mgmt_ev_user_confirm_request ev;
3381
Johan Hedberg744cf192011-11-08 20:40:14 +02003382 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003383
Johan Hedberg272d90d2012-02-09 15:26:12 +02003384 bacpy(&ev.addr.bdaddr, bdaddr);
3385 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003386 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003387 put_unaligned_le32(value, &ev.value);
3388
Johan Hedberg744cf192011-11-08 20:40:14 +02003389 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003390 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003391}
3392
Johan Hedberg272d90d2012-02-09 15:26:12 +02003393int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3394 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003395{
3396 struct mgmt_ev_user_passkey_request ev;
3397
3398 BT_DBG("%s", hdev->name);
3399
Johan Hedberg272d90d2012-02-09 15:26:12 +02003400 bacpy(&ev.addr.bdaddr, bdaddr);
3401 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003402
3403 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3404 NULL);
3405}
3406
Brian Gix0df4c182011-11-16 13:53:13 -08003407static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003408 u8 link_type, u8 addr_type, u8 status,
3409 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003410{
3411 struct pending_cmd *cmd;
3412 struct mgmt_rp_user_confirm_reply rp;
3413 int err;
3414
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003415 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003416 if (!cmd)
3417 return -ENOENT;
3418
Johan Hedberg272d90d2012-02-09 15:26:12 +02003419 bacpy(&rp.addr.bdaddr, bdaddr);
3420 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003421 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3422 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003423
Johan Hedberga664b5b2011-02-19 12:06:02 -03003424 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003425
3426 return err;
3427}
3428
Johan Hedberg744cf192011-11-08 20:40:14 +02003429int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003430 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003431{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003432 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3433 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003434}
3435
Johan Hedberg272d90d2012-02-09 15:26:12 +02003436int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3437 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003438{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003439 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3440 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003441}
Johan Hedberg2a611692011-02-19 12:06:00 -03003442
Brian Gix604086b2011-11-23 08:28:33 -08003443int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003444 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003445{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003446 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3447 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003448}
3449
Johan Hedberg272d90d2012-02-09 15:26:12 +02003450int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3451 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003452{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003453 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3454 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003455}
3456
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003457int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3458 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003459{
3460 struct mgmt_ev_auth_failed ev;
3461
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003462 bacpy(&ev.addr.bdaddr, bdaddr);
3463 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003464 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003465
Johan Hedberg744cf192011-11-08 20:40:14 +02003466 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003467}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003468
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003469int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3470{
3471 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003472 bool changed = false;
3473 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003474
3475 if (status) {
3476 u8 mgmt_err = mgmt_status(status);
3477 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3478 cmd_status_rsp, &mgmt_err);
3479 return 0;
3480 }
3481
Johan Hedberg47990ea2012-02-22 11:58:37 +02003482 if (test_bit(HCI_AUTH, &hdev->flags)) {
3483 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3484 changed = true;
3485 } else {
3486 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3487 changed = true;
3488 }
3489
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003490 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3491 &match);
3492
Johan Hedberg47990ea2012-02-22 11:58:37 +02003493 if (changed)
3494 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003495
3496 if (match.sk)
3497 sock_put(match.sk);
3498
3499 return err;
3500}
3501
Johan Hedbergcacaf522012-02-21 00:52:42 +02003502static int clear_eir(struct hci_dev *hdev)
3503{
3504 struct hci_cp_write_eir cp;
3505
3506 if (!(hdev->features[6] & LMP_EXT_INQ))
3507 return 0;
3508
Johan Hedbergc80da272012-02-22 15:38:48 +02003509 memset(hdev->eir, 0, sizeof(hdev->eir));
3510
Johan Hedbergcacaf522012-02-21 00:52:42 +02003511 memset(&cp, 0, sizeof(cp));
3512
3513 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3514}
3515
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003516int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003517{
3518 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003519 bool changed = false;
3520 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003521
3522 if (status) {
3523 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003524
3525 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3526 &hdev->dev_flags))
3527 err = new_settings(hdev, NULL);
3528
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003529 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3530 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003531
3532 return err;
3533 }
3534
3535 if (enable) {
3536 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3537 changed = true;
3538 } else {
3539 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3540 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003541 }
3542
3543 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3544
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003545 if (changed)
3546 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003547
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003548 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003549 sock_put(match.sk);
3550
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003551 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3552 update_eir(hdev);
3553 else
3554 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003555
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003556 return err;
3557}
3558
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003559int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3560 u8 status)
3561{
3562 int err;
3563
3564 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL);
3565
3566 return err;
3567}
3568
Johan Hedberg744cf192011-11-08 20:40:14 +02003569int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003570{
3571 struct pending_cmd *cmd;
3572 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003573 bool changed = false;
3574 int err = 0;
3575
3576 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3577 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3578 changed = true;
3579 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003580
3581 memset(&ev, 0, sizeof(ev));
3582 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003583 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003584
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003585 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003586 if (!cmd)
3587 goto send_event;
3588
3589 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003590 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003591 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003592 goto failed;
3593 }
3594
Johan Hedbergaee9b212012-02-18 15:07:59 +02003595 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003596 sizeof(ev));
3597 if (err < 0)
3598 goto failed;
3599
3600send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003601 if (changed)
3602 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
3603 sizeof(ev), cmd ? cmd->sk : NULL);
3604
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003605 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003606
3607failed:
3608 if (cmd)
3609 mgmt_pending_remove(cmd);
3610 return err;
3611}
Szymon Jancc35938b2011-03-22 13:12:21 +01003612
Johan Hedberg744cf192011-11-08 20:40:14 +02003613int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3614 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003615{
3616 struct pending_cmd *cmd;
3617 int err;
3618
Johan Hedberg744cf192011-11-08 20:40:14 +02003619 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003620
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003621 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003622 if (!cmd)
3623 return -ENOENT;
3624
3625 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003626 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003627 MGMT_OP_READ_LOCAL_OOB_DATA,
3628 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003629 } else {
3630 struct mgmt_rp_read_local_oob_data rp;
3631
3632 memcpy(rp.hash, hash, sizeof(rp.hash));
3633 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3634
Johan Hedberg744cf192011-11-08 20:40:14 +02003635 err = cmd_complete(cmd->sk, hdev->id,
3636 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003637 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003638 }
3639
3640 mgmt_pending_remove(cmd);
3641
3642 return err;
3643}
Johan Hedberge17acd42011-03-30 23:57:16 +03003644
Johan Hedberg06199cf2012-02-22 16:37:11 +02003645int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3646{
3647 struct cmd_lookup match = { NULL, hdev };
3648 bool changed = false;
3649 int err = 0;
3650
3651 if (status) {
3652 u8 mgmt_err = mgmt_status(status);
3653
3654 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
3655 &hdev->dev_flags))
3656 err = new_settings(hdev, NULL);
3657
3658 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
3659 cmd_status_rsp, &mgmt_err);
3660
3661 return err;
3662 }
3663
3664 if (enable) {
3665 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3666 changed = true;
3667 } else {
3668 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3669 changed = true;
3670 }
3671
3672 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3673
3674 if (changed)
3675 err = new_settings(hdev, match.sk);
3676
3677 if (match.sk)
3678 sock_put(match.sk);
3679
3680 return err;
3681}
3682
Johan Hedberg48264f02011-11-09 13:58:58 +02003683int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003684 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003685 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003686{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003687 char buf[512];
3688 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003689 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003690
Johan Hedberg1dc06092012-01-15 21:01:23 +02003691 /* Leave 5 bytes for a potential CoD field */
3692 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003693 return -EINVAL;
3694
Johan Hedberg1dc06092012-01-15 21:01:23 +02003695 memset(buf, 0, sizeof(buf));
3696
Johan Hedberge319d2e2012-01-15 19:51:59 +02003697 bacpy(&ev->addr.bdaddr, bdaddr);
3698 ev->addr.type = link_to_mgmt(link_type, addr_type);
3699 ev->rssi = rssi;
3700 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003701
Johan Hedberg1dc06092012-01-15 21:01:23 +02003702 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003703 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003704
Johan Hedberg1dc06092012-01-15 21:01:23 +02003705 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3706 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3707 dev_class, 3);
3708
3709 put_unaligned_le16(eir_len, &ev->eir_len);
3710
3711 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003712
Johan Hedberge319d2e2012-01-15 19:51:59 +02003713 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003714}
Johan Hedberga88a9652011-03-30 13:18:12 +03003715
Johan Hedbergb644ba32012-01-17 21:48:47 +02003716int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3717 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003718{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003719 struct mgmt_ev_device_found *ev;
3720 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3721 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003722
Johan Hedbergb644ba32012-01-17 21:48:47 +02003723 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003724
Johan Hedbergb644ba32012-01-17 21:48:47 +02003725 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003726
Johan Hedbergb644ba32012-01-17 21:48:47 +02003727 bacpy(&ev->addr.bdaddr, bdaddr);
3728 ev->addr.type = link_to_mgmt(link_type, addr_type);
3729 ev->rssi = rssi;
3730
3731 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3732 name_len);
3733
3734 put_unaligned_le16(eir_len, &ev->eir_len);
3735
Johan Hedberg053c7e02012-02-04 00:06:00 +02003736 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3737 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003738}
Johan Hedberg314b2382011-04-27 10:29:57 -04003739
Andre Guedes7a135102011-11-09 17:14:25 -03003740int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003741{
3742 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003743 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003744 int err;
3745
Andre Guedes203159d2012-02-13 15:41:01 -03003746 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3747
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003748 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003749 if (!cmd)
3750 return -ENOENT;
3751
Johan Hedbergf808e162012-02-19 12:52:07 +02003752 type = hdev->discovery.type;
3753
3754 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3755 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003756 mgmt_pending_remove(cmd);
3757
3758 return err;
3759}
3760
Andre Guedese6d465c2011-11-09 17:14:26 -03003761int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3762{
3763 struct pending_cmd *cmd;
3764 int err;
3765
3766 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3767 if (!cmd)
3768 return -ENOENT;
3769
Johan Hedbergd9306502012-02-20 23:25:18 +02003770 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3771 &hdev->discovery.type,
3772 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003773 mgmt_pending_remove(cmd);
3774
3775 return err;
3776}
Johan Hedberg314b2382011-04-27 10:29:57 -04003777
Johan Hedberg744cf192011-11-08 20:40:14 +02003778int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003779{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003780 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003781 struct pending_cmd *cmd;
3782
Andre Guedes343fb142011-11-22 17:14:19 -03003783 BT_DBG("%s discovering %u", hdev->name, discovering);
3784
Johan Hedberg164a6e72011-11-01 17:06:44 +02003785 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003786 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003787 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003788 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003789
3790 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003791 u8 type = hdev->discovery.type;
3792
Johan Hedbergd9306502012-02-20 23:25:18 +02003793 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003794 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003795 mgmt_pending_remove(cmd);
3796 }
3797
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003798 memset(&ev, 0, sizeof(ev));
3799 ev.type = hdev->discovery.type;
3800 ev.discovering = discovering;
3801
3802 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003803}
Antti Julku5e762442011-08-25 16:48:02 +03003804
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003805int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003806{
3807 struct pending_cmd *cmd;
3808 struct mgmt_ev_device_blocked ev;
3809
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003810 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003811
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003812 bacpy(&ev.addr.bdaddr, bdaddr);
3813 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003814
Johan Hedberg744cf192011-11-08 20:40:14 +02003815 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3816 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003817}
3818
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003819int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003820{
3821 struct pending_cmd *cmd;
3822 struct mgmt_ev_device_unblocked ev;
3823
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003824 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003825
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003826 bacpy(&ev.addr.bdaddr, bdaddr);
3827 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003828
Johan Hedberg744cf192011-11-08 20:40:14 +02003829 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3830 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003831}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003832
3833module_param(enable_hs, bool, 0644);
3834MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3835
3836module_param(enable_le, bool, 0644);
3837MODULE_PARM_DESC(enable_le, "Enable Low Energy support");