blob: 8f3d9dc7013d56e61e9245d517fa96a5ab977b0f [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
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800119#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200120
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,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300237 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
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
271 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200272{
273 struct mgmt_rp_read_version rp;
274
275 BT_DBG("sock %p", sk);
276
277 rp.version = MGMT_VERSION;
278 put_unaligned_le16(MGMT_REVISION, &rp.revision);
279
Johan Hedbergaee9b212012-02-18 15:07:59 +0200280 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300281 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200282}
283
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300284static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
285 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200286{
287 struct mgmt_rp_read_commands *rp;
288 u16 num_commands = ARRAY_SIZE(mgmt_commands);
289 u16 num_events = ARRAY_SIZE(mgmt_events);
290 u16 *opcode;
291 size_t rp_size;
292 int i, err;
293
294 BT_DBG("sock %p", sk);
295
296 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
297
298 rp = kmalloc(rp_size, GFP_KERNEL);
299 if (!rp)
300 return -ENOMEM;
301
302 put_unaligned_le16(num_commands, &rp->num_commands);
303 put_unaligned_le16(num_events, &rp->num_events);
304
305 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
306 put_unaligned_le16(mgmt_commands[i], opcode);
307
308 for (i = 0; i < num_events; i++, opcode++)
309 put_unaligned_le16(mgmt_events[i], opcode);
310
Johan Hedbergaee9b212012-02-18 15:07:59 +0200311 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300312 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200313 kfree(rp);
314
315 return err;
316}
317
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300318static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
319 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200320{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321 struct mgmt_rp_read_index_list *rp;
322 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200323 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200324 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327
328 BT_DBG("sock %p", sk);
329
330 read_lock(&hci_dev_list_lock);
331
332 count = 0;
333 list_for_each(p, &hci_dev_list) {
334 count++;
335 }
336
Johan Hedberga38528f2011-01-22 06:46:43 +0200337 rp_len = sizeof(*rp) + (2 * count);
338 rp = kmalloc(rp_len, GFP_ATOMIC);
339 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100340 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100342 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344 put_unaligned_le16(count, &rp->num_controllers);
345
346 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200347 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200348 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200349 continue;
350
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200351 put_unaligned_le16(d->id, &rp->index[i++]);
352 BT_DBG("Added hci%u", d->id);
353 }
354
355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b212012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
370 settings |= MGMT_SETTING_CONNECTABLE;
371 settings |= MGMT_SETTING_FAST_CONNECTABLE;
372 settings |= MGMT_SETTING_DISCOVERABLE;
373 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (hdev->features[6] & LMP_SIMPLE_PAIR)
376 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 if (!(hdev->features[4] & LMP_NO_BREDR)) {
379 settings |= MGMT_SETTING_BREDR;
380 settings |= MGMT_SETTING_LINK_SECURITY;
381 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200382
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 if (enable_hs)
384 settings |= MGMT_SETTING_HS;
385
386 if (enable_le) {
387 if (hdev->features[4] & LMP_LE)
388 settings |= MGMT_SETTING_LE;
389 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Johan Hedberg06199cf2012-02-22 16:37:11 +0200413 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg47990ea2012-02-22 11:58:37 +0200416 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200538 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200539 return 0;
540
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300541 if (!(hdev->features[6] & LMP_EXT_INQ))
542 return 0;
543
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200544 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200547 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548 return 0;
549
550 memset(&cp, 0, sizeof(cp));
551
552 create_eir(hdev, cp.data);
553
554 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
555 return 0;
556
557 memcpy(hdev->eir, cp.data, sizeof(cp.data));
558
559 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
560}
561
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562static u8 get_service_classes(struct hci_dev *hdev)
563{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 u8 val = 0;
566
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300567 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200568 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200569
570 return val;
571}
572
573static int update_class(struct hci_dev *hdev)
574{
575 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200576 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577
578 BT_DBG("%s", hdev->name);
579
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200580 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200581 return 0;
582
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200583 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584 return 0;
585
586 cod[0] = hdev->minor_class;
587 cod[1] = hdev->major_class;
588 cod[2] = get_service_classes(hdev);
589
590 if (memcmp(cod, hdev->dev_class, 3) == 0)
591 return 0;
592
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200593 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
594 if (err == 0)
595 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
596
597 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200598}
599
Johan Hedberg7d785252011-12-15 00:47:39 +0200600static void service_cache_off(struct work_struct *work)
601{
602 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300603 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200604
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200605 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200606 return;
607
608 hci_dev_lock(hdev);
609
610 update_eir(hdev);
611 update_class(hdev);
612
613 hci_dev_unlock(hdev);
614}
615
Johan Hedberg6a919082012-02-28 06:17:26 +0200616static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200617{
Johan Hedberg4f87da802012-03-02 19:55:56 +0200618 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200619 return;
620
Johan Hedberg4f87da802012-03-02 19:55:56 +0200621 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200622
Johan Hedberg4f87da802012-03-02 19:55:56 +0200623 /* Non-mgmt controlled devices get this bit set
624 * implicitly so that pairing works for them, however
625 * for mgmt we require user-space to explicitly enable
626 * it
627 */
628 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200629}
630
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200631static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300632 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200633{
634 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200635
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200636 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300638 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
Johan Hedberg03811012010-12-08 00:21:06 +0200640 memset(&rp, 0, sizeof(rp));
641
Johan Hedberg03811012010-12-08 00:21:06 +0200642 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200643
644 rp.version = hdev->hci_ver;
645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200647
648 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
649 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
650
651 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200652
653 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200654 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200655
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300656 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200657
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200658 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300659 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200660}
661
662static void mgmt_pending_free(struct pending_cmd *cmd)
663{
664 sock_put(cmd->sk);
665 kfree(cmd->param);
666 kfree(cmd);
667}
668
669static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300670 struct hci_dev *hdev, void *data,
671 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200672{
673 struct pending_cmd *cmd;
674
675 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
676 if (!cmd)
677 return NULL;
678
679 cmd->opcode = opcode;
680 cmd->index = hdev->id;
681
682 cmd->param = kmalloc(len, GFP_ATOMIC);
683 if (!cmd->param) {
684 kfree(cmd);
685 return NULL;
686 }
687
688 if (data)
689 memcpy(cmd->param, data, len);
690
691 cmd->sk = sk;
692 sock_hold(sk);
693
694 list_add(&cmd->list, &hdev->mgmt_pending);
695
696 return cmd;
697}
698
699static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300700 void (*cb)(struct pending_cmd *cmd, void *data),
701 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200702{
703 struct list_head *p, *n;
704
705 list_for_each_safe(p, n, &hdev->mgmt_pending) {
706 struct pending_cmd *cmd;
707
708 cmd = list_entry(p, struct pending_cmd, list);
709
710 if (opcode > 0 && cmd->opcode != opcode)
711 continue;
712
713 cb(cmd, data);
714 }
715}
716
717static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
718{
719 struct pending_cmd *cmd;
720
721 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
722 if (cmd->opcode == opcode)
723 return cmd;
724 }
725
726 return NULL;
727}
728
729static void mgmt_pending_remove(struct pending_cmd *cmd)
730{
731 list_del(&cmd->list);
732 mgmt_pending_free(cmd);
733}
734
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200735static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200736{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200737 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200738
Johan Hedbergaee9b212012-02-18 15:07:59 +0200739 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300740 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200741}
742
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200743static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300744 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200745{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300746 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200747 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200748 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200749
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200750 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300752 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100754 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
755 cancel_delayed_work(&hdev->power_off);
756
757 if (cp->val) {
758 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
759 mgmt_powered(hdev, 1);
760 goto failed;
761 }
762 }
763
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200764 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200765 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766 goto failed;
767 }
768
769 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200770 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300771 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200772 goto failed;
773 }
774
775 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
776 if (!cmd) {
777 err = -ENOMEM;
778 goto failed;
779 }
780
781 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200782 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200784 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200785
786 err = 0;
787
788failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300789 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200790 return err;
791}
792
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300793static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
794 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200795{
796 struct sk_buff *skb;
797 struct mgmt_hdr *hdr;
798
799 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
800 if (!skb)
801 return -ENOMEM;
802
803 hdr = (void *) skb_put(skb, sizeof(*hdr));
804 hdr->opcode = cpu_to_le16(event);
805 if (hdev)
806 hdr->index = cpu_to_le16(hdev->id);
807 else
808 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
809 hdr->len = cpu_to_le16(data_len);
810
811 if (data)
812 memcpy(skb_put(skb, data_len), data, data_len);
813
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100814 /* Time stamp */
815 __net_timestamp(skb);
816
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200817 hci_send_to_control(skb, skip_sk);
818 kfree_skb(skb);
819
820 return 0;
821}
822
823static int new_settings(struct hci_dev *hdev, struct sock *skip)
824{
825 __le32 ev;
826
827 ev = cpu_to_le32(get_current_settings(hdev));
828
829 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
830}
831
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200832static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300833 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200834{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300835 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200836 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200837 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200838 u8 scan;
839 int err;
840
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200841 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200842
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100843 timeout = get_unaligned_le16(&cp->timeout);
844 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200845 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300846 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200847
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300848 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200849
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200850 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200851 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300852 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200853 goto failed;
854 }
855
856 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
857 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200858 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300859 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200860 goto failed;
861 }
862
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200863 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200864 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300865 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200866 goto failed;
867 }
868
869 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200870 bool changed = false;
871
872 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
873 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
874 changed = true;
875 }
876
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200877 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200878 if (err < 0)
879 goto failed;
880
881 if (changed)
882 err = new_settings(hdev, sk);
883
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200884 goto failed;
885 }
886
887 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100888 if (hdev->discov_timeout > 0) {
889 cancel_delayed_work(&hdev->discov_off);
890 hdev->discov_timeout = 0;
891 }
892
893 if (cp->val && timeout > 0) {
894 hdev->discov_timeout = timeout;
895 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
896 msecs_to_jiffies(hdev->discov_timeout * 1000));
897 }
898
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200899 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200900 goto failed;
901 }
902
903 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
904 if (!cmd) {
905 err = -ENOMEM;
906 goto failed;
907 }
908
909 scan = SCAN_PAGE;
910
911 if (cp->val)
912 scan |= SCAN_INQUIRY;
913 else
914 cancel_delayed_work(&hdev->discov_off);
915
916 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
917 if (err < 0)
918 mgmt_pending_remove(cmd);
919
Johan Hedberg03811012010-12-08 00:21:06 +0200920 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200921 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200922
923failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300924 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200925 return err;
926}
927
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200928static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300929 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200930{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300931 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200932 struct pending_cmd *cmd;
933 u8 scan;
934 int err;
935
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200936 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300938 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200940 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200941 bool changed = false;
942
943 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
944 changed = true;
945
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200946 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200947 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200948 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200949 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
950 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
951 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200952
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200953 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200954 if (err < 0)
955 goto failed;
956
957 if (changed)
958 err = new_settings(hdev, sk);
959
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200960 goto failed;
961 }
962
963 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
964 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200965 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300966 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200967 goto failed;
968 }
969
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200971 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972 goto failed;
973 }
974
975 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
976 if (!cmd) {
977 err = -ENOMEM;
978 goto failed;
979 }
980
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200981 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200983 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 scan = 0;
985
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200986 if (test_bit(HCI_ISCAN, &hdev->flags) &&
987 hdev->discov_timeout > 0)
988 cancel_delayed_work(&hdev->discov_off);
989 }
990
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200991 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
992 if (err < 0)
993 mgmt_pending_remove(cmd);
994
995failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300996 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200997 return err;
998}
999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001000static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001001 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001002{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001003 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001004 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001006 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001008 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009
1010 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001011 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001012 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001013 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001015 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016 if (err < 0)
1017 goto failed;
1018
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001019 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020
1021failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001022 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023 return err;
1024}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001025
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001026static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1027 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001028{
1029 struct mgmt_mode *cp = data;
1030 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001031 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001032 int err;
1033
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001034 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001035
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001036 hci_dev_lock(hdev);
1037
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001038 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001039 bool changed = false;
1040
1041 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1042 &hdev->dev_flags)) {
1043 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1044 changed = true;
1045 }
1046
1047 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1048 if (err < 0)
1049 goto failed;
1050
1051 if (changed)
1052 err = new_settings(hdev, sk);
1053
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001054 goto failed;
1055 }
1056
1057 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001058 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001059 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001060 goto failed;
1061 }
1062
1063 val = !!cp->val;
1064
1065 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1066 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1067 goto failed;
1068 }
1069
1070 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1071 if (!cmd) {
1072 err = -ENOMEM;
1073 goto failed;
1074 }
1075
1076 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1077 if (err < 0) {
1078 mgmt_pending_remove(cmd);
1079 goto failed;
1080 }
1081
1082failed:
1083 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001084 return err;
1085}
1086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001087static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001088{
1089 struct mgmt_mode *cp = data;
1090 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001091 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001092 int err;
1093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001094 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001095
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001096 hci_dev_lock(hdev);
1097
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001098 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001099 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001100 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001101 goto failed;
1102 }
1103
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001104 val = !!cp->val;
1105
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001106 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001107 bool changed = false;
1108
1109 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1110 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1111 changed = true;
1112 }
1113
1114 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1115 if (err < 0)
1116 goto failed;
1117
1118 if (changed)
1119 err = new_settings(hdev, sk);
1120
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001121 goto failed;
1122 }
1123
1124 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001125 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1126 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001127 goto failed;
1128 }
1129
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001130 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1131 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1132 goto failed;
1133 }
1134
1135 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1136 if (!cmd) {
1137 err = -ENOMEM;
1138 goto failed;
1139 }
1140
1141 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1142 if (err < 0) {
1143 mgmt_pending_remove(cmd);
1144 goto failed;
1145 }
1146
1147failed:
1148 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001149 return err;
1150}
1151
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001152static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001153{
1154 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001156 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001158 if (!enable_hs)
1159 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001160 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001161
1162 if (cp->val)
1163 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1164 else
1165 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001167 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001168}
1169
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001170static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001171{
1172 struct mgmt_mode *cp = data;
1173 struct hci_cp_write_le_host_supported hci_cp;
1174 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001175 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001176 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001179
Johan Hedberg1de028c2012-02-29 19:55:35 -08001180 hci_dev_lock(hdev);
1181
Johan Hedberg06199cf2012-02-22 16:37:11 +02001182 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001183 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001184 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001185 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001186 }
1187
1188 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001189 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001190
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001191 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001192 bool changed = false;
1193
1194 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1195 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1196 changed = true;
1197 }
1198
1199 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1200 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001201 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202
1203 if (changed)
1204 err = new_settings(hdev, sk);
1205
Johan Hedberg1de028c2012-02-29 19:55:35 -08001206 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001207 }
1208
1209 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001210 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001211 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001212 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001213 }
1214
1215 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1216 if (!cmd) {
1217 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001218 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001219 }
1220
1221 memset(&hci_cp, 0, sizeof(hci_cp));
1222
1223 if (val) {
1224 hci_cp.le = val;
1225 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1226 }
1227
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001228 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1229 &hci_cp);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001230 if (err < 0) {
1231 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001232 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001233 }
1234
Johan Hedberg1de028c2012-02-29 19:55:35 -08001235unlock:
1236 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001237 return err;
1238}
1239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001240static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001241{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001242 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001243 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001244 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001245 int err;
1246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001247 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001249 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001250
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001251 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001252 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001253 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001254 goto failed;
1255 }
1256
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001257 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1258 if (!uuid) {
1259 err = -ENOMEM;
1260 goto failed;
1261 }
1262
1263 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001264 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001265
1266 list_add(&uuid->list, &hdev->uuids);
1267
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001268 err = update_class(hdev);
1269 if (err < 0)
1270 goto failed;
1271
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001272 err = update_eir(hdev);
1273 if (err < 0)
1274 goto failed;
1275
Johan Hedberg90e70452012-02-23 23:09:40 +02001276 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001278 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001279 goto failed;
1280 }
1281
1282 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1283 if (!cmd) {
1284 err = -ENOMEM;
1285 goto failed;
1286 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001287
1288failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001289 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001290 return err;
1291}
1292
Johan Hedberg24b78d02012-02-23 23:24:30 +02001293static bool enable_service_cache(struct hci_dev *hdev)
1294{
1295 if (!hdev_is_powered(hdev))
1296 return false;
1297
1298 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001299 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001300 return true;
1301 }
1302
1303 return false;
1304}
1305
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001306static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1307 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001308{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001309 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001310 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001311 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 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 +02001313 int err, found;
1314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001315 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001316
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001317 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001318
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001319 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001320 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001321 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001322 goto unlock;
1323 }
1324
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1326 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001327
Johan Hedberg24b78d02012-02-23 23:24:30 +02001328 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001329 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001330 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001331 goto unlock;
1332 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001333
Johan Hedberg9246a862012-02-23 21:33:16 +02001334 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 }
1336
1337 found = 0;
1338
1339 list_for_each_safe(p, n, &hdev->uuids) {
1340 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1341
1342 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1343 continue;
1344
1345 list_del(&match->list);
1346 found++;
1347 }
1348
1349 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001350 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001351 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352 goto unlock;
1353 }
1354
Johan Hedberg9246a862012-02-23 21:33:16 +02001355update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001356 err = update_class(hdev);
1357 if (err < 0)
1358 goto unlock;
1359
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001360 err = update_eir(hdev);
1361 if (err < 0)
1362 goto unlock;
1363
Johan Hedberg90e70452012-02-23 23:09:40 +02001364 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001365 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001366 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001367 goto unlock;
1368 }
1369
1370 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1371 if (!cmd) {
1372 err = -ENOMEM;
1373 goto unlock;
1374 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001375
1376unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001377 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001378 return err;
1379}
1380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001381static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001382 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001383{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001384 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001385 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001386 int err;
1387
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001388 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001389
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001390 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001391
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001392 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001394 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001395 goto unlock;
1396 }
1397
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001398 hdev->major_class = cp->major;
1399 hdev->minor_class = cp->minor;
1400
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001401 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001402 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001403 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001404 goto unlock;
1405 }
1406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001407 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001408 hci_dev_unlock(hdev);
1409 cancel_delayed_work_sync(&hdev->service_cache);
1410 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001411 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001412 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001413
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001414 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001415 if (err < 0)
1416 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001417
Johan Hedberg90e70452012-02-23 23:09:40 +02001418 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001419 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001420 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001421 goto unlock;
1422 }
1423
1424 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1425 if (!cmd) {
1426 err = -ENOMEM;
1427 goto unlock;
1428 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001429
Johan Hedbergb5235a62012-02-21 14:32:24 +02001430unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001431 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001432 return err;
1433}
1434
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001435static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1436 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001437{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001438 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001439 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001440 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001441
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001442 key_count = get_unaligned_le16(&cp->key_count);
1443
Johan Hedberg86742e12011-11-07 23:13:38 +02001444 expected_len = sizeof(*cp) + key_count *
1445 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001446 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001447 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001448 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001450 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001451 }
1452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001453 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001454 key_count);
1455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001456 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001457
1458 hci_link_keys_clear(hdev);
1459
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001460 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001461
1462 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001463 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001464 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001465 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001466
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001467 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001468 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001469
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001470 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001471 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001472 }
1473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001474 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001477
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001478 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001479}
1480
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001481static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001482 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001483{
1484 struct mgmt_ev_device_unpaired ev;
1485
1486 bacpy(&ev.addr.bdaddr, bdaddr);
1487 ev.addr.type = addr_type;
1488
1489 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001490 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001491}
1492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001493static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001494 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001495{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001496 struct mgmt_cp_unpair_device *cp = data;
1497 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001498 struct hci_cp_disconnect dc;
1499 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001500 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001501 int err;
1502
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001503 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001504
Johan Hedberga8a1d192011-11-10 15:54:38 +02001505 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001506 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1507 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001508
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001509 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001510 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001511 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001512 goto unlock;
1513 }
1514
Johan Hedberg124f6e32012-02-09 13:50:12 +02001515 if (cp->addr.type == MGMT_ADDR_BREDR)
1516 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1517 else
1518 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001519
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001520 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001521 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001522 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001523 goto unlock;
1524 }
1525
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001526 if (cp->disconnect) {
1527 if (cp->addr.type == MGMT_ADDR_BREDR)
1528 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1529 &cp->addr.bdaddr);
1530 else
1531 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1532 &cp->addr.bdaddr);
1533 } else {
1534 conn = NULL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001535 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001536
Johan Hedberga8a1d192011-11-10 15:54:38 +02001537 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001538 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001539 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001540 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001541 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001542 }
1543
Johan Hedberg124f6e32012-02-09 13:50:12 +02001544 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001545 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001546 if (!cmd) {
1547 err = -ENOMEM;
1548 goto unlock;
1549 }
1550
1551 put_unaligned_le16(conn->handle, &dc.handle);
1552 dc.reason = 0x13; /* Remote User Terminated Connection */
1553 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1554 if (err < 0)
1555 mgmt_pending_remove(cmd);
1556
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001557unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001558 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001559 return err;
1560}
1561
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001562static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001563 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001564{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001565 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001566 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001567 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001568 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001569 int err;
1570
1571 BT_DBG("");
1572
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001573 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001574
1575 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001576 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001577 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001578 goto failed;
1579 }
1580
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001581 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001582 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001583 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001584 goto failed;
1585 }
1586
Johan Hedberg88c3df12012-02-09 14:27:38 +02001587 if (cp->addr.type == MGMT_ADDR_BREDR)
1588 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1589 else
1590 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001591
Johan Hedberg8962ee72011-01-20 12:40:27 +02001592 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001593 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001594 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001595 goto failed;
1596 }
1597
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001598 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001599 if (!cmd) {
1600 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001601 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001602 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001603
1604 put_unaligned_le16(conn->handle, &dc.handle);
1605 dc.reason = 0x13; /* Remote User Terminated Connection */
1606
1607 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1608 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001609 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001610
1611failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001612 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001613 return err;
1614}
1615
Johan Hedberg48264f02011-11-09 13:58:58 +02001616static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001617{
1618 switch (link_type) {
1619 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001620 switch (addr_type) {
1621 case ADDR_LE_DEV_PUBLIC:
1622 return MGMT_ADDR_LE_PUBLIC;
1623 case ADDR_LE_DEV_RANDOM:
1624 return MGMT_ADDR_LE_RANDOM;
1625 default:
1626 return MGMT_ADDR_INVALID;
1627 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001628 case ACL_LINK:
1629 return MGMT_ADDR_BREDR;
1630 default:
1631 return MGMT_ADDR_INVALID;
1632 }
1633}
1634
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001635static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1636 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001637{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001638 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001639 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001640 size_t rp_len;
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001641 int err;
1642 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001643
1644 BT_DBG("");
1645
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001646 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001647
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001648 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001649 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001650 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001651 goto unlock;
1652 }
1653
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001654 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001655 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1656 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001657 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001658 }
1659
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001660 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001661 rp = kmalloc(rp_len, GFP_ATOMIC);
1662 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001663 err = -ENOMEM;
1664 goto unlock;
1665 }
1666
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001668 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001669 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1670 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001671 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001672 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001673 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1674 continue;
1675 i++;
1676 }
1677
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001678 put_unaligned_le16(i, &rp->conn_count);
1679
Johan Hedberg4c659c32011-11-07 23:13:39 +02001680 /* Recalculate length in case of filtered SCO connections, etc */
1681 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001682
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001683 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001684 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001685
Johan Hedberga38528f2011-01-22 06:46:43 +02001686 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001687
1688unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001689 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001690 return err;
1691}
1692
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001693static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001694 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001695{
1696 struct pending_cmd *cmd;
1697 int err;
1698
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001699 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001700 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001701 if (!cmd)
1702 return -ENOMEM;
1703
Johan Hedbergd8457692012-02-17 14:24:57 +02001704 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001705 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001706 if (err < 0)
1707 mgmt_pending_remove(cmd);
1708
1709 return err;
1710}
1711
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001712static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001713 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001714{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001715 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001716 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001717 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001718 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001719 int err;
1720
1721 BT_DBG("");
1722
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001723 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001724
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001725 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001726 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001727 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001728 goto failed;
1729 }
1730
Johan Hedbergd8457692012-02-17 14:24:57 +02001731 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001732 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001733 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001734 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001735 goto failed;
1736 }
1737
1738 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001739 struct mgmt_cp_pin_code_neg_reply ncp;
1740
1741 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001742
1743 BT_ERR("PIN code is not 16 bytes long");
1744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001745 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001746 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001747 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001748 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001749
1750 goto failed;
1751 }
1752
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001753 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001754 if (!cmd) {
1755 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001756 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001757 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001758
Johan Hedbergd8457692012-02-17 14:24:57 +02001759 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001760 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001761 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001762
1763 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1764 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001765 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001766
1767failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001768 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001769 return err;
1770}
1771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001772static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001773 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001774{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001775 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001776 int err;
1777
1778 BT_DBG("");
1779
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001780 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001781
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001782 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001783 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001784 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785 goto failed;
1786 }
1787
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001788 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789
1790failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001791 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001792 return err;
1793}
1794
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001795static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1796 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001798 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001799
1800 BT_DBG("");
1801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001802 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001803
1804 hdev->io_capability = cp->io_capability;
1805
1806 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001807 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001808
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001809 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001810
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001811 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1812 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001813}
1814
Johan Hedberge9a416b2011-02-19 12:05:56 -03001815static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1816{
1817 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001818 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001819
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001820 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001821 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1822 continue;
1823
Johan Hedberge9a416b2011-02-19 12:05:56 -03001824 if (cmd->user_data != conn)
1825 continue;
1826
1827 return cmd;
1828 }
1829
1830 return NULL;
1831}
1832
1833static void pairing_complete(struct pending_cmd *cmd, u8 status)
1834{
1835 struct mgmt_rp_pair_device rp;
1836 struct hci_conn *conn = cmd->user_data;
1837
Johan Hedbergba4e5642011-11-11 00:07:34 +02001838 bacpy(&rp.addr.bdaddr, &conn->dst);
1839 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001840
Johan Hedbergaee9b212012-02-18 15:07:59 +02001841 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843
1844 /* So we don't get further callbacks for this connection */
1845 conn->connect_cfm_cb = NULL;
1846 conn->security_cfm_cb = NULL;
1847 conn->disconn_cfm_cb = NULL;
1848
1849 hci_conn_put(conn);
1850
Johan Hedberga664b5b2011-02-19 12:06:02 -03001851 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001852}
1853
1854static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1855{
1856 struct pending_cmd *cmd;
1857
1858 BT_DBG("status %u", status);
1859
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001860 cmd = find_pairing(conn);
1861 if (!cmd)
1862 BT_DBG("Unable to find a pending command");
1863 else
Johan Hedberge2113262012-02-18 15:20:03 +02001864 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001865}
1866
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001867static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001868 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001869{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001870 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001871 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001872 struct pending_cmd *cmd;
1873 u8 sec_level, auth_type;
1874 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001875 int err;
1876
1877 BT_DBG("");
1878
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001879 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001880
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001881 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001882 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001883 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001884 goto unlock;
1885 }
1886
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001887 sec_level = BT_SECURITY_MEDIUM;
1888 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001890 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001892
Johan Hedbergba4e5642011-11-11 00:07:34 +02001893 if (cp->addr.type == MGMT_ADDR_BREDR)
1894 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001895 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001896 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001897 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001898 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001899
Johan Hedberg1425acb2011-11-11 00:07:35 +02001900 memset(&rp, 0, sizeof(rp));
1901 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1902 rp.addr.type = cp->addr.type;
1903
Ville Tervo30e76272011-02-22 16:10:53 -03001904 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001905 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001906 MGMT_STATUS_CONNECT_FAILED, &rp,
1907 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001908 goto unlock;
1909 }
1910
1911 if (conn->connect_cfm_cb) {
1912 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001913 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001914 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001915 goto unlock;
1916 }
1917
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001918 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001919 if (!cmd) {
1920 err = -ENOMEM;
1921 hci_conn_put(conn);
1922 goto unlock;
1923 }
1924
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001925 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001926 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001927 conn->connect_cfm_cb = pairing_complete_cb;
1928
Johan Hedberge9a416b2011-02-19 12:05:56 -03001929 conn->security_cfm_cb = pairing_complete_cb;
1930 conn->disconn_cfm_cb = pairing_complete_cb;
1931 conn->io_capability = cp->io_cap;
1932 cmd->user_data = conn;
1933
1934 if (conn->state == BT_CONNECTED &&
1935 hci_conn_security(conn, sec_level, auth_type))
1936 pairing_complete(cmd, 0);
1937
1938 err = 0;
1939
1940unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001941 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001942 return err;
1943}
1944
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001945static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1946 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001947{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001948 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001949 struct pending_cmd *cmd;
1950 struct hci_conn *conn;
1951 int err;
1952
1953 BT_DBG("");
1954
Johan Hedberg28424702012-02-02 04:02:29 +02001955 hci_dev_lock(hdev);
1956
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001957 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001958 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001959 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001960 goto unlock;
1961 }
1962
Johan Hedberg28424702012-02-02 04:02:29 +02001963 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1964 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001965 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001966 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001967 goto unlock;
1968 }
1969
1970 conn = cmd->user_data;
1971
1972 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001973 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001974 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001975 goto unlock;
1976 }
1977
1978 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1979
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001980 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001981 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001982unlock:
1983 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02001984 return err;
1985}
1986
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001987static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001988 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
1989 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001990{
Johan Hedberga5c29682011-02-19 12:05:57 -03001991 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08001992 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001993 int err;
1994
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001995 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001996
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001997 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001998 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001999 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002000 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002001 }
2002
Johan Hedberg272d90d2012-02-09 15:26:12 +02002003 if (type == MGMT_ADDR_BREDR)
2004 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2005 else
Brian Gix47c15e22011-11-16 13:53:14 -08002006 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002007
Johan Hedberg272d90d2012-02-09 15:26:12 +02002008 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002009 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002011 goto done;
2012 }
2013
2014 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002015 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002016 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002017
Brian Gix5fe57d92011-12-21 16:12:13 -08002018 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002019 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002020 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002021 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002022 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002023 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002024
Brian Gix47c15e22011-11-16 13:53:14 -08002025 goto done;
2026 }
2027
Brian Gix0df4c182011-11-16 13:53:13 -08002028 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002029 if (!cmd) {
2030 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002031 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002032 }
2033
Brian Gix0df4c182011-11-16 13:53:13 -08002034 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002035 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2036 struct hci_cp_user_passkey_reply cp;
2037
2038 bacpy(&cp.bdaddr, bdaddr);
2039 cp.passkey = passkey;
2040 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2041 } else
2042 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2043
Johan Hedberga664b5b2011-02-19 12:06:02 -03002044 if (err < 0)
2045 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002046
Brian Gix0df4c182011-11-16 13:53:13 -08002047done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002048 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002049 return err;
2050}
2051
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002052static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2053 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002054{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002055 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002056
2057 BT_DBG("");
2058
2059 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002060 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002061 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002063 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002064 MGMT_OP_USER_CONFIRM_REPLY,
2065 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002066}
2067
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002068static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002069 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002070{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002071 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002072
2073 BT_DBG("");
2074
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002075 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002076 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2077 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002078}
2079
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002080static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2081 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002082{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002083 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002084
2085 BT_DBG("");
2086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002087 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002088 MGMT_OP_USER_PASSKEY_REPLY,
2089 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002090}
2091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002094{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002095 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002096
2097 BT_DBG("");
2098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002099 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002100 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2101 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002102}
2103
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002104static int update_name(struct hci_dev *hdev, const char *name)
2105{
2106 struct hci_cp_write_local_name cp;
2107
2108 memcpy(cp.name, name, sizeof(cp.name));
2109
2110 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2111}
2112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002113static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002114 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002115{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002116 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002117 struct pending_cmd *cmd;
2118 int err;
2119
2120 BT_DBG("");
2121
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002122 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002123
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002124 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002125
Johan Hedbergb5235a62012-02-21 14:32:24 +02002126 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002127 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002128
2129 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002130 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002131 if (err < 0)
2132 goto failed;
2133
2134 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002135 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002136
Johan Hedbergb5235a62012-02-21 14:32:24 +02002137 goto failed;
2138 }
2139
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002140 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002141 if (!cmd) {
2142 err = -ENOMEM;
2143 goto failed;
2144 }
2145
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002146 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002147 if (err < 0)
2148 mgmt_pending_remove(cmd);
2149
2150failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002151 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002152 return err;
2153}
2154
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002155static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002156 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002157{
Szymon Jancc35938b2011-03-22 13:12:21 +01002158 struct pending_cmd *cmd;
2159 int err;
2160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002161 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002162
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002163 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002164
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002165 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002166 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002167 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002168 goto unlock;
2169 }
2170
2171 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002172 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002173 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002174 goto unlock;
2175 }
2176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002177 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002178 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002179 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002180 goto unlock;
2181 }
2182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002183 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184 if (!cmd) {
2185 err = -ENOMEM;
2186 goto unlock;
2187 }
2188
2189 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2190 if (err < 0)
2191 mgmt_pending_remove(cmd);
2192
2193unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002194 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002195 return err;
2196}
2197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002198static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002200{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002201 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002202 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002203 int err;
2204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002205 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002208
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002209 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002210 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002211 MGMT_STATUS_NOT_POWERED, &cp->addr,
2212 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002213 goto unlock;
2214 }
2215
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002216 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002217 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002218 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002219 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002220 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002221 status = 0;
2222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002223 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002224 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002225
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002226unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002227 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002228 return err;
2229}
2230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002232 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002233{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002234 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002235 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002236 int err;
2237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002238 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002239
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002241
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002242 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002243 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002244 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2245 MGMT_STATUS_NOT_POWERED, &cp->addr,
2246 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002247 goto unlock;
2248 }
2249
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002250 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002251 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002252 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002253 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002254 status = 0;
2255
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002256 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002257 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002258
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002259unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002260 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261 return err;
2262}
2263
Andre Guedes5e0452c2012-02-17 20:39:38 -03002264int mgmt_interleaved_discovery(struct hci_dev *hdev)
2265{
2266 int err;
2267
2268 BT_DBG("%s", hdev->name);
2269
2270 hci_dev_lock(hdev);
2271
2272 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2273 if (err < 0)
2274 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2275
2276 hci_dev_unlock(hdev);
2277
2278 return err;
2279}
2280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002281static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002282 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002283{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002284 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002285 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002286 int err;
2287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002288 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002289
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002290 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002291
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002292 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002293 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002294 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002295 goto failed;
2296 }
2297
Johan Hedbergff9ef572012-01-04 14:23:45 +02002298 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002300 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002301 goto failed;
2302 }
2303
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002304 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002305 if (!cmd) {
2306 err = -ENOMEM;
2307 goto failed;
2308 }
2309
Andre Guedes4aab14e2012-02-17 20:39:36 -03002310 hdev->discovery.type = cp->type;
2311
2312 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002313 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002314 if (lmp_bredr_capable(hdev))
2315 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2316 else
2317 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002318 break;
2319
2320 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002321 if (lmp_host_le_capable(hdev))
2322 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002324 else
2325 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002326 break;
2327
Andre Guedes5e0452c2012-02-17 20:39:38 -03002328 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002329 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2330 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002331 LE_SCAN_WIN,
2332 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002333 else
2334 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002335 break;
2336
Andre Guedesf39799f2012-02-17 20:39:35 -03002337 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002338 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002339 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002340
Johan Hedberg14a53662011-04-27 10:29:56 -04002341 if (err < 0)
2342 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002343 else
2344 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002345
2346failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002347 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002348 return err;
2349}
2350
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002351static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002352 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002353{
Johan Hedbergd9306502012-02-20 23:25:18 +02002354 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002355 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002356 struct hci_cp_remote_name_req_cancel cp;
2357 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002358 int err;
2359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002361
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002362 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002363
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002364 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002365 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002366 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2367 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002368 goto unlock;
2369 }
2370
2371 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002372 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002373 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2374 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002375 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002376 }
2377
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002378 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002379 if (!cmd) {
2380 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002381 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002382 }
2383
Andre Guedes343f9352012-02-17 20:39:37 -03002384 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002385 err = hci_cancel_inquiry(hdev);
2386 if (err < 0)
2387 mgmt_pending_remove(cmd);
2388 else
2389 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2390 goto unlock;
2391 }
2392
2393 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2394 if (!e) {
2395 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002396 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002397 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002398 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2399 goto unlock;
2400 }
2401
2402 bacpy(&cp.bdaddr, &e->data.bdaddr);
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002403 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2404 &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002405 if (err < 0)
2406 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002407 else
2408 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002409
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002410unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002411 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002412 return err;
2413}
2414
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002415static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002417{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002418 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002419 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002420 int err;
2421
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002422 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002423
Johan Hedberg561aafb2012-01-04 13:31:59 +02002424 hci_dev_lock(hdev);
2425
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002426 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002427 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002428 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002429 goto failed;
2430 }
2431
Johan Hedberga198e7b2012-02-17 14:27:06 +02002432 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002433 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002434 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002436 goto failed;
2437 }
2438
2439 if (cp->name_known) {
2440 e->name_state = NAME_KNOWN;
2441 list_del(&e->list);
2442 } else {
2443 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002444 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002445 }
2446
2447 err = 0;
2448
2449failed:
2450 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002451 return err;
2452}
2453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002456{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002457 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002458 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002459 int err;
2460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002464
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002465 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002466 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002467 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002468 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002469 status = 0;
2470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002471 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002472 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002474 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002475
2476 return err;
2477}
2478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002481{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002482 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002483 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002484 int err;
2485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002486 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002487
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002488 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002489
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002490 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002491 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002492 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002493 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002494 status = 0;
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002498
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002499 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002500
2501 return err;
2502}
2503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002504static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002505 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002506{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002508 struct hci_cp_write_page_scan_activity acp;
2509 u8 type;
2510 int err;
2511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002513
Johan Hedberg5400c042012-02-21 16:40:33 +02002514 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002515 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002516 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002517
2518 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002519 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002520 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002521
2522 hci_dev_lock(hdev);
2523
Johan Hedbergf7c68692011-12-15 00:47:36 +02002524 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002525 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002526
2527 /* 22.5 msec page scan interval */
2528 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002529 } else {
2530 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002531
2532 /* default 1.28 sec page scan */
2533 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002534 }
2535
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002536 /* default 11.25 msec page scan window */
2537 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002538
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2540 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002541 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002542 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002543 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002544 goto done;
2545 }
2546
2547 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2548 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002549 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002550 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002551 goto done;
2552 }
2553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002554 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002556done:
2557 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002558 return err;
2559}
2560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002561static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002562 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002563{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002564 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2565 u16 key_count, expected_len;
2566 int i;
2567
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002568 key_count = get_unaligned_le16(&cp->key_count);
2569
2570 expected_len = sizeof(*cp) + key_count *
2571 sizeof(struct mgmt_ltk_info);
2572 if (expected_len != len) {
2573 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2574 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002575 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002576 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002577 }
2578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002579 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002580
2581 hci_dev_lock(hdev);
2582
2583 hci_smp_ltks_clear(hdev);
2584
2585 for (i = 0; i < key_count; i++) {
2586 struct mgmt_ltk_info *key = &cp->keys[i];
2587 u8 type;
2588
2589 if (key->master)
2590 type = HCI_SMP_LTK;
2591 else
2592 type = HCI_SMP_LTK_SLAVE;
2593
2594 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002595 type, 0, key->authenticated, key->val,
2596 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002597 }
2598
2599 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002600
2601 return 0;
2602}
2603
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002604struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002605 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2606 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002607 bool var_len;
2608 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002609} mgmt_handlers[] = {
2610 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002611 { read_version, false, MGMT_READ_VERSION_SIZE },
2612 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2613 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2614 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2615 { set_powered, false, MGMT_SETTING_SIZE },
2616 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2617 { set_connectable, false, MGMT_SETTING_SIZE },
2618 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2619 { set_pairable, false, MGMT_SETTING_SIZE },
2620 { set_link_security, false, MGMT_SETTING_SIZE },
2621 { set_ssp, false, MGMT_SETTING_SIZE },
2622 { set_hs, false, MGMT_SETTING_SIZE },
2623 { set_le, false, MGMT_SETTING_SIZE },
2624 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2625 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2626 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2627 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2628 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2629 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2630 { disconnect, false, MGMT_DISCONNECT_SIZE },
2631 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2632 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2633 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2634 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2635 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2636 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2637 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2638 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2639 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2640 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2641 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2642 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2643 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2644 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2645 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2646 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2647 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2648 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2649 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002650};
2651
2652
Johan Hedberg03811012010-12-08 00:21:06 +02002653int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2654{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002655 void *buf;
2656 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002657 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002658 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002659 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002660 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002661 int err;
2662
2663 BT_DBG("got %zu bytes", msglen);
2664
2665 if (msglen < sizeof(*hdr))
2666 return -EINVAL;
2667
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002668 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002669 if (!buf)
2670 return -ENOMEM;
2671
2672 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2673 err = -EFAULT;
2674 goto done;
2675 }
2676
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002677 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002678 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002679 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002680 len = get_unaligned_le16(&hdr->len);
2681
2682 if (len != msglen - sizeof(*hdr)) {
2683 err = -EINVAL;
2684 goto done;
2685 }
2686
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002687 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002688 hdev = hci_dev_get(index);
2689 if (!hdev) {
2690 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002691 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002692 goto done;
2693 }
2694 }
2695
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002696 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2697 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002698 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002699 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002701 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002702 }
2703
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002704 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2705 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2706 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002707 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002708 goto done;
2709 }
2710
Johan Hedbergbe22b542012-03-01 22:24:41 +02002711 handler = &mgmt_handlers[opcode];
2712
2713 if ((handler->var_len && len < handler->data_len) ||
2714 (!handler->var_len && len != handler->data_len)) {
2715 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002716 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002717 goto done;
2718 }
2719
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002720 if (hdev)
2721 mgmt_init_hdev(sk, hdev);
2722
2723 cp = buf + sizeof(*hdr);
2724
Johan Hedbergbe22b542012-03-01 22:24:41 +02002725 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002726 if (err < 0)
2727 goto done;
2728
Johan Hedberg03811012010-12-08 00:21:06 +02002729 err = msglen;
2730
2731done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002732 if (hdev)
2733 hci_dev_put(hdev);
2734
Johan Hedberg03811012010-12-08 00:21:06 +02002735 kfree(buf);
2736 return err;
2737}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002738
Johan Hedbergb24752f2011-11-03 14:40:33 +02002739static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2740{
2741 u8 *status = data;
2742
2743 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2744 mgmt_pending_remove(cmd);
2745}
2746
Johan Hedberg744cf192011-11-08 20:40:14 +02002747int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002748{
Johan Hedberg744cf192011-11-08 20:40:14 +02002749 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002750}
2751
Johan Hedberg744cf192011-11-08 20:40:14 +02002752int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002753{
Johan Hedberg5f159032012-03-02 03:13:19 +02002754 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002755
Johan Hedberg744cf192011-11-08 20:40:14 +02002756 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002757
Johan Hedberg744cf192011-11-08 20:40:14 +02002758 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002759}
2760
Johan Hedberg73f22f62010-12-29 16:00:25 +02002761struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002762 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002763 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002764 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002765};
2766
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002767static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002768{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002769 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002770
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002771 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002772
2773 list_del(&cmd->list);
2774
2775 if (match->sk == NULL) {
2776 match->sk = cmd->sk;
2777 sock_hold(match->sk);
2778 }
2779
2780 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002781}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002782
Johan Hedberg744cf192011-11-08 20:40:14 +02002783int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002784{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002785 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002786 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002787
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002788 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2789 return 0;
2790
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002791 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002792
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002793 if (powered) {
2794 u8 scan = 0;
2795
2796 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2797 scan |= SCAN_PAGE;
2798 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2799 scan |= SCAN_INQUIRY;
2800
2801 if (scan)
2802 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002803
Andrzej Kaczmarekdcc8dbc2012-08-29 10:02:08 +02002804 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
2805 u8 ssp = 1;
2806
2807 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
2808 }
2809
Andrzej Kaczmareka6be20b2012-08-29 10:02:09 +02002810 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
2811 struct hci_cp_write_le_host_supported cp;
2812
2813 cp.le = 1;
2814 cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
2815
2816 hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
2817 sizeof(cp), &cp);
2818 }
2819
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002820 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002821 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002822 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002823 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002824 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002825 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002826 }
2827
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002828 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002829
2830 if (match.sk)
2831 sock_put(match.sk);
2832
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002833 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002834}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002835
Johan Hedberg744cf192011-11-08 20:40:14 +02002836int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002837{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002838 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002839 bool changed = false;
2840 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002841
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002842 if (discoverable) {
2843 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2844 changed = true;
2845 } else {
2846 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2847 changed = true;
2848 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002849
Johan Hedberged9b5f22012-02-21 20:47:06 +02002850 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002851 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002852
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002853 if (changed)
2854 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002855
Johan Hedberg73f22f62010-12-29 16:00:25 +02002856 if (match.sk)
2857 sock_put(match.sk);
2858
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002859 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002860}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002861
Johan Hedberg744cf192011-11-08 20:40:14 +02002862int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002863{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002864 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002865 bool changed = false;
2866 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002867
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002868 if (connectable) {
2869 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2870 changed = true;
2871 } else {
2872 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2873 changed = true;
2874 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002875
Johan Hedberged9b5f22012-02-21 20:47:06 +02002876 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002877 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002878
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002879 if (changed)
2880 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002881
2882 if (match.sk)
2883 sock_put(match.sk);
2884
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002885 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002886}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002887
Johan Hedberg744cf192011-11-08 20:40:14 +02002888int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002889{
Johan Hedbergca69b792011-11-11 18:10:00 +02002890 u8 mgmt_err = mgmt_status(status);
2891
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002892 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002893 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002894 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002895
2896 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002897 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002898 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002899
2900 return 0;
2901}
2902
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302903int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002904{
Johan Hedberg86742e12011-11-07 23:13:38 +02002905 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002906
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002907 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002908
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002909 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002910 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2911 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002912 ev.key.type = key->type;
2913 memcpy(ev.key.val, key->val, 16);
2914 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002915
Johan Hedberg744cf192011-11-08 20:40:14 +02002916 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002917}
Johan Hedbergf7520542011-01-20 12:34:39 +02002918
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002919int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2920{
2921 struct mgmt_ev_new_long_term_key ev;
2922
2923 memset(&ev, 0, sizeof(ev));
2924
2925 ev.store_hint = persistent;
2926 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2927 ev.key.addr.type = key->bdaddr_type;
2928 ev.key.authenticated = key->authenticated;
2929 ev.key.enc_size = key->enc_size;
2930 ev.key.ediv = key->ediv;
2931
2932 if (key->type == HCI_SMP_LTK)
2933 ev.key.master = 1;
2934
2935 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2936 memcpy(ev.key.val, key->val, sizeof(key->val));
2937
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002938 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2939 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002940}
2941
Johan Hedbergafc747a2012-01-15 18:11:07 +02002942int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002943 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2944 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002945{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002946 char buf[512];
2947 struct mgmt_ev_device_connected *ev = (void *) buf;
2948 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002949
Johan Hedbergb644ba32012-01-17 21:48:47 +02002950 bacpy(&ev->addr.bdaddr, bdaddr);
2951 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002952
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002953 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002954
Johan Hedbergb644ba32012-01-17 21:48:47 +02002955 if (name_len > 0)
2956 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002958
2959 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08002960 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002961 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002962
2963 put_unaligned_le16(eir_len, &ev->eir_len);
2964
2965 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002966 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002967}
2968
Johan Hedberg8962ee72011-01-20 12:40:27 +02002969static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2970{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002971 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002972 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002973 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002974
Johan Hedberg88c3df12012-02-09 14:27:38 +02002975 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2976 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002977
Johan Hedbergaee9b212012-02-18 15:07:59 +02002978 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002979 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002980
2981 *sk = cmd->sk;
2982 sock_hold(*sk);
2983
Johan Hedberga664b5b2011-02-19 12:06:02 -03002984 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002985}
2986
Johan Hedberg124f6e32012-02-09 13:50:12 +02002987static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002988{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002989 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002990 struct mgmt_cp_unpair_device *cp = cmd->param;
2991 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002992
2993 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002994 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2995 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002996
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002997 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2998
Johan Hedbergaee9b212012-02-18 15:07:59 +02002999 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003000
3001 mgmt_pending_remove(cmd);
3002}
3003
Johan Hedbergafc747a2012-01-15 18:11:07 +02003004int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003006{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003007 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003008 struct sock *sk = NULL;
3009 int err;
3010
Johan Hedberg744cf192011-11-08 20:40:14 +02003011 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003012
Johan Hedbergf7520542011-01-20 12:34:39 +02003013 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003014 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003015
Johan Hedbergafc747a2012-01-15 18:11:07 +02003016 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003017 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003018
3019 if (sk)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003020 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003021
Johan Hedberg124f6e32012-02-09 13:50:12 +02003022 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003024
Johan Hedberg8962ee72011-01-20 12:40:27 +02003025 return err;
3026}
3027
Johan Hedberg88c3df12012-02-09 14:27:38 +02003028int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003030{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003031 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003032 struct pending_cmd *cmd;
3033 int err;
3034
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003035 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003036 if (!cmd)
3037 return -ENOENT;
3038
Johan Hedberg88c3df12012-02-09 14:27:38 +02003039 bacpy(&rp.addr.bdaddr, bdaddr);
3040 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003041
Johan Hedberg88c3df12012-02-09 14:27:38 +02003042 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003043 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003044
Johan Hedberga664b5b2011-02-19 12:06:02 -03003045 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003046
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003047 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3048 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003049 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003050}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003051
Johan Hedberg48264f02011-11-09 13:58:58 +02003052int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003053 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003054{
3055 struct mgmt_ev_connect_failed ev;
3056
Johan Hedberg4c659c32011-11-07 23:13:39 +02003057 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003058 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003059 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003060
Johan Hedberg744cf192011-11-08 20:40:14 +02003061 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003062}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003063
Johan Hedberg744cf192011-11-08 20:40:14 +02003064int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003065{
3066 struct mgmt_ev_pin_code_request ev;
3067
Johan Hedbergd8457692012-02-17 14:24:57 +02003068 bacpy(&ev.addr.bdaddr, bdaddr);
3069 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003070 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003071
Johan Hedberg744cf192011-11-08 20:40:14 +02003072 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003073 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003074}
3075
Johan Hedberg744cf192011-11-08 20:40:14 +02003076int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003077 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003078{
3079 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003080 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003081 int err;
3082
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003083 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003084 if (!cmd)
3085 return -ENOENT;
3086
Johan Hedbergd8457692012-02-17 14:24:57 +02003087 bacpy(&rp.addr.bdaddr, bdaddr);
3088 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003089
Johan Hedbergaee9b212012-02-18 15:07:59 +02003090 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003091 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003092
Johan Hedberga664b5b2011-02-19 12:06:02 -03003093 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003094
3095 return err;
3096}
3097
Johan Hedberg744cf192011-11-08 20:40:14 +02003098int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003099 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003100{
3101 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003102 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003103 int err;
3104
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003105 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003106 if (!cmd)
3107 return -ENOENT;
3108
Johan Hedbergd8457692012-02-17 14:24:57 +02003109 bacpy(&rp.addr.bdaddr, bdaddr);
3110 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003111
Johan Hedbergaee9b212012-02-18 15:07:59 +02003112 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003113 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003114
Johan Hedberga664b5b2011-02-19 12:06:02 -03003115 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003116
3117 return err;
3118}
Johan Hedberga5c29682011-02-19 12:05:57 -03003119
Johan Hedberg744cf192011-11-08 20:40:14 +02003120int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003121 u8 link_type, u8 addr_type, __le32 value,
3122 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003123{
3124 struct mgmt_ev_user_confirm_request ev;
3125
Johan Hedberg744cf192011-11-08 20:40:14 +02003126 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003127
Johan Hedberg272d90d2012-02-09 15:26:12 +02003128 bacpy(&ev.addr.bdaddr, bdaddr);
3129 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003130 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003131 put_unaligned_le32(value, &ev.value);
3132
Johan Hedberg744cf192011-11-08 20:40:14 +02003133 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003134 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003135}
3136
Johan Hedberg272d90d2012-02-09 15:26:12 +02003137int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3138 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003139{
3140 struct mgmt_ev_user_passkey_request ev;
3141
3142 BT_DBG("%s", hdev->name);
3143
Johan Hedberg272d90d2012-02-09 15:26:12 +02003144 bacpy(&ev.addr.bdaddr, bdaddr);
3145 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003146
3147 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003148 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003149}
3150
Brian Gix0df4c182011-11-16 13:53:13 -08003151static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003152 u8 link_type, u8 addr_type, u8 status,
3153 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003154{
3155 struct pending_cmd *cmd;
3156 struct mgmt_rp_user_confirm_reply rp;
3157 int err;
3158
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003159 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003160 if (!cmd)
3161 return -ENOENT;
3162
Johan Hedberg272d90d2012-02-09 15:26:12 +02003163 bacpy(&rp.addr.bdaddr, bdaddr);
3164 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003165 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003166 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003167
Johan Hedberga664b5b2011-02-19 12:06:02 -03003168 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003169
3170 return err;
3171}
3172
Johan Hedberg744cf192011-11-08 20:40:14 +02003173int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003174 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003175{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003176 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003177 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003178}
3179
Johan Hedberg272d90d2012-02-09 15:26:12 +02003180int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003181 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003182{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003183 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003184 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003185}
Johan Hedberg2a611692011-02-19 12:06:00 -03003186
Brian Gix604086b2011-11-23 08:28:33 -08003187int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003188 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003189{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003190 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003191 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003192}
3193
Johan Hedberg272d90d2012-02-09 15:26:12 +02003194int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003195 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003196{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003197 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003198 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003199}
3200
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003201int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003202 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003203{
3204 struct mgmt_ev_auth_failed ev;
3205
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003206 bacpy(&ev.addr.bdaddr, bdaddr);
3207 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003208 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003209
Johan Hedberg744cf192011-11-08 20:40:14 +02003210 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003211}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003212
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003213int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3214{
3215 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003216 bool changed = false;
3217 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003218
3219 if (status) {
3220 u8 mgmt_err = mgmt_status(status);
3221 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003222 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003223 return 0;
3224 }
3225
Johan Hedberg47990ea2012-02-22 11:58:37 +02003226 if (test_bit(HCI_AUTH, &hdev->flags)) {
3227 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3228 changed = true;
3229 } else {
3230 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3231 changed = true;
3232 }
3233
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003234 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003235 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003236
Johan Hedberg47990ea2012-02-22 11:58:37 +02003237 if (changed)
3238 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003239
3240 if (match.sk)
3241 sock_put(match.sk);
3242
3243 return err;
3244}
3245
Johan Hedbergcacaf522012-02-21 00:52:42 +02003246static int clear_eir(struct hci_dev *hdev)
3247{
3248 struct hci_cp_write_eir cp;
3249
3250 if (!(hdev->features[6] & LMP_EXT_INQ))
3251 return 0;
3252
Johan Hedbergc80da272012-02-22 15:38:48 +02003253 memset(hdev->eir, 0, sizeof(hdev->eir));
3254
Johan Hedbergcacaf522012-02-21 00:52:42 +02003255 memset(&cp, 0, sizeof(cp));
3256
3257 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3258}
3259
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003260int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003261{
3262 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003263 bool changed = false;
3264 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003265
3266 if (status) {
3267 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003268
3269 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003270 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003271 err = new_settings(hdev, NULL);
3272
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003273 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3274 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003275
3276 return err;
3277 }
3278
3279 if (enable) {
3280 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3281 changed = true;
3282 } else {
3283 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3284 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003285 }
3286
3287 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3288
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003289 if (changed)
3290 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003291
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003292 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003293 sock_put(match.sk);
3294
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003295 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3296 update_eir(hdev);
3297 else
3298 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003299
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003300 return err;
3301}
3302
Johan Hedberg90e70452012-02-23 23:09:40 +02003303static void class_rsp(struct pending_cmd *cmd, void *data)
3304{
3305 struct cmd_lookup *match = data;
3306
3307 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003308 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003309
3310 list_del(&cmd->list);
3311
3312 if (match->sk == NULL) {
3313 match->sk = cmd->sk;
3314 sock_hold(match->sk);
3315 }
3316
3317 mgmt_pending_free(cmd);
3318}
3319
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003320int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003321 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003322{
Johan Hedberg90e70452012-02-23 23:09:40 +02003323 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3324 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003325
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003326 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3327
Johan Hedberg90e70452012-02-23 23:09:40 +02003328 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3329 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3330 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3331
3332 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003333 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3334 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003335
3336 if (match.sk)
3337 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003338
3339 return err;
3340}
3341
Johan Hedberg744cf192011-11-08 20:40:14 +02003342int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003343{
3344 struct pending_cmd *cmd;
3345 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003346 bool changed = false;
3347 int err = 0;
3348
3349 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3350 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3351 changed = true;
3352 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003353
3354 memset(&ev, 0, sizeof(ev));
3355 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003356 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003357
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003358 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003359 if (!cmd)
3360 goto send_event;
3361
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003362 /* Always assume that either the short or the complete name has
3363 * changed if there was a pending mgmt command */
3364 changed = true;
3365
Johan Hedbergb312b1612011-03-16 14:29:37 +02003366 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003367 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003368 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003369 goto failed;
3370 }
3371
Johan Hedbergaee9b212012-02-18 15:07:59 +02003372 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003373 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003374 if (err < 0)
3375 goto failed;
3376
3377send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003378 if (changed)
3379 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003380 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003381
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003382 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003383
3384failed:
3385 if (cmd)
3386 mgmt_pending_remove(cmd);
3387 return err;
3388}
Szymon Jancc35938b2011-03-22 13:12:21 +01003389
Johan Hedberg744cf192011-11-08 20:40:14 +02003390int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003391 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003392{
3393 struct pending_cmd *cmd;
3394 int err;
3395
Johan Hedberg744cf192011-11-08 20:40:14 +02003396 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003397
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003398 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003399 if (!cmd)
3400 return -ENOENT;
3401
3402 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003403 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3404 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003405 } else {
3406 struct mgmt_rp_read_local_oob_data rp;
3407
3408 memcpy(rp.hash, hash, sizeof(rp.hash));
3409 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3410
Johan Hedberg744cf192011-11-08 20:40:14 +02003411 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003412 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3413 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003414 }
3415
3416 mgmt_pending_remove(cmd);
3417
3418 return err;
3419}
Johan Hedberge17acd42011-03-30 23:57:16 +03003420
Johan Hedberg06199cf2012-02-22 16:37:11 +02003421int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3422{
3423 struct cmd_lookup match = { NULL, hdev };
3424 bool changed = false;
3425 int err = 0;
3426
3427 if (status) {
3428 u8 mgmt_err = mgmt_status(status);
3429
3430 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003431 &hdev->dev_flags))
3432 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003433
3434 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003435 cmd_status_rsp, &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003436
3437 return err;
3438 }
3439
3440 if (enable) {
3441 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3442 changed = true;
3443 } else {
3444 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3445 changed = true;
3446 }
3447
3448 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3449
3450 if (changed)
3451 err = new_settings(hdev, match.sk);
3452
3453 if (match.sk)
3454 sock_put(match.sk);
3455
3456 return err;
3457}
3458
Johan Hedberg48264f02011-11-09 13:58:58 +02003459int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003460 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3461 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003462{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003463 char buf[512];
3464 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003465 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003466
Johan Hedberg1dc06092012-01-15 21:01:23 +02003467 /* Leave 5 bytes for a potential CoD field */
3468 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003469 return -EINVAL;
3470
Johan Hedberg1dc06092012-01-15 21:01:23 +02003471 memset(buf, 0, sizeof(buf));
3472
Johan Hedberge319d2e2012-01-15 19:51:59 +02003473 bacpy(&ev->addr.bdaddr, bdaddr);
3474 ev->addr.type = link_to_mgmt(link_type, addr_type);
3475 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003476 if (cfm_name)
3477 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003478 if (!ssp)
3479 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003480
Johan Hedberg1dc06092012-01-15 21:01:23 +02003481 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003482 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003483
Johan Hedberg1dc06092012-01-15 21:01:23 +02003484 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3485 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003486 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003487
3488 put_unaligned_le16(eir_len, &ev->eir_len);
3489
3490 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003491
Johan Hedberge319d2e2012-01-15 19:51:59 +02003492 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003493}
Johan Hedberga88a9652011-03-30 13:18:12 +03003494
Johan Hedbergb644ba32012-01-17 21:48:47 +02003495int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003496 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003497{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003498 struct mgmt_ev_device_found *ev;
3499 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3500 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003501
Johan Hedbergb644ba32012-01-17 21:48:47 +02003502 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003503
Johan Hedbergb644ba32012-01-17 21:48:47 +02003504 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003505
Johan Hedbergb644ba32012-01-17 21:48:47 +02003506 bacpy(&ev->addr.bdaddr, bdaddr);
3507 ev->addr.type = link_to_mgmt(link_type, addr_type);
3508 ev->rssi = rssi;
3509
3510 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003511 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003512
3513 put_unaligned_le16(eir_len, &ev->eir_len);
3514
Johan Hedberg053c7e02012-02-04 00:06:00 +02003515 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003516 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003517}
Johan Hedberg314b2382011-04-27 10:29:57 -04003518
Andre Guedes7a135102011-11-09 17:14:25 -03003519int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003520{
3521 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003522 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003523 int err;
3524
Andre Guedes203159d2012-02-13 15:41:01 -03003525 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3526
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003527 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003528 if (!cmd)
3529 return -ENOENT;
3530
Johan Hedbergf808e162012-02-19 12:52:07 +02003531 type = hdev->discovery.type;
3532
3533 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003534 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003535 mgmt_pending_remove(cmd);
3536
3537 return err;
3538}
3539
Andre Guedese6d465c2011-11-09 17:14:26 -03003540int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3541{
3542 struct pending_cmd *cmd;
3543 int err;
3544
3545 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3546 if (!cmd)
3547 return -ENOENT;
3548
Johan Hedbergd9306502012-02-20 23:25:18 +02003549 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003550 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003551 mgmt_pending_remove(cmd);
3552
3553 return err;
3554}
Johan Hedberg314b2382011-04-27 10:29:57 -04003555
Johan Hedberg744cf192011-11-08 20:40:14 +02003556int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003557{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003558 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003559 struct pending_cmd *cmd;
3560
Andre Guedes343fb142011-11-22 17:14:19 -03003561 BT_DBG("%s discovering %u", hdev->name, discovering);
3562
Johan Hedberg164a6e72011-11-01 17:06:44 +02003563 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003564 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003565 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003566 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003567
3568 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003569 u8 type = hdev->discovery.type;
3570
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003571 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3572 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003573 mgmt_pending_remove(cmd);
3574 }
3575
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003576 memset(&ev, 0, sizeof(ev));
3577 ev.type = hdev->discovery.type;
3578 ev.discovering = discovering;
3579
3580 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003581}
Antti Julku5e762442011-08-25 16:48:02 +03003582
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003583int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003584{
3585 struct pending_cmd *cmd;
3586 struct mgmt_ev_device_blocked ev;
3587
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003588 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003589
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003590 bacpy(&ev.addr.bdaddr, bdaddr);
3591 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003592
Johan Hedberg744cf192011-11-08 20:40:14 +02003593 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003594 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003595}
3596
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003597int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003598{
3599 struct pending_cmd *cmd;
3600 struct mgmt_ev_device_unblocked ev;
3601
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003602 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003603
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003604 bacpy(&ev.addr.bdaddr, bdaddr);
3605 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003606
Johan Hedberg744cf192011-11-08 20:40:14 +02003607 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003608 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003609}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003610
3611module_param(enable_hs, bool, 0644);
3612MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3613
3614module_param(enable_le, bool, 0644);
3615MODULE_PARM_DESC(enable_le, "Enable Low Energy support");