blob: 02b89e299ff8d561fdbd0878edbe5993a83b0fbb [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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700482 if (hdev->inq_tx_power) {
483 ptr[0] = 2;
484 ptr[1] = EIR_TX_POWER;
485 ptr[2] = (u8) hdev->inq_tx_power;
486
487 eir_len += 3;
488 ptr += 3;
489 }
490
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300491 memset(uuid16_list, 0, sizeof(uuid16_list));
492
493 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200494 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300495 u16 uuid16;
496
497 uuid16 = get_uuid16(uuid->uuid);
498 if (uuid16 == 0)
499 return;
500
501 if (uuid16 < 0x1100)
502 continue;
503
504 if (uuid16 == PNP_INFO_SVCLASS_ID)
505 continue;
506
507 /* Stop if not enough space to put next UUID */
508 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
509 truncated = 1;
510 break;
511 }
512
513 /* Check for duplicates */
514 for (i = 0; uuid16_list[i] != 0; i++)
515 if (uuid16_list[i] == uuid16)
516 break;
517
518 if (uuid16_list[i] == 0) {
519 uuid16_list[i] = uuid16;
520 eir_len += sizeof(u16);
521 }
522 }
523
524 if (uuid16_list[0] != 0) {
525 u8 *length = ptr;
526
527 /* EIR Data type */
528 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
529
530 ptr += 2;
531 eir_len += 2;
532
533 for (i = 0; uuid16_list[i] != 0; i++) {
534 *ptr++ = (uuid16_list[i] & 0x00ff);
535 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
536 }
537
538 /* EIR Data length */
539 *length = (i * sizeof(u16)) + 1;
540 }
541}
542
543static int update_eir(struct hci_dev *hdev)
544{
545 struct hci_cp_write_eir cp;
546
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200547 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200548 return 0;
549
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300550 if (!(hdev->features[6] & LMP_EXT_INQ))
551 return 0;
552
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200553 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300554 return 0;
555
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200556 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300557 return 0;
558
559 memset(&cp, 0, sizeof(cp));
560
561 create_eir(hdev, cp.data);
562
563 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
564 return 0;
565
566 memcpy(hdev->eir, cp.data, sizeof(cp.data));
567
568 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
569}
570
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200571static u8 get_service_classes(struct hci_dev *hdev)
572{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300573 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 u8 val = 0;
575
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300576 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200578
579 return val;
580}
581
582static int update_class(struct hci_dev *hdev)
583{
584 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200585 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200586
587 BT_DBG("%s", hdev->name);
588
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200589 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200590 return 0;
591
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200592 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200593 return 0;
594
595 cod[0] = hdev->minor_class;
596 cod[1] = hdev->major_class;
597 cod[2] = get_service_classes(hdev);
598
599 if (memcmp(cod, hdev->dev_class, 3) == 0)
600 return 0;
601
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200602 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
603 if (err == 0)
604 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
605
606 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200607}
608
Johan Hedberg7d785252011-12-15 00:47:39 +0200609static void service_cache_off(struct work_struct *work)
610{
611 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300612 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200613
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200614 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200615 return;
616
617 hci_dev_lock(hdev);
618
619 update_eir(hdev);
620 update_class(hdev);
621
622 hci_dev_unlock(hdev);
623}
624
Johan Hedberg6a919082012-02-28 06:17:26 +0200625static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200626{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200627 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200628 return;
629
Johan Hedberg4f87da82012-03-02 19:55:56 +0200630 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200631
Johan Hedberg4f87da82012-03-02 19:55:56 +0200632 /* Non-mgmt controlled devices get this bit set
633 * implicitly so that pairing works for them, however
634 * for mgmt we require user-space to explicitly enable
635 * it
636 */
637 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200638}
639
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200640static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300641 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200642{
643 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200644
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200645 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200646
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300647 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200648
Johan Hedberg03811012010-12-08 00:21:06 +0200649 memset(&rp, 0, sizeof(rp));
650
Johan Hedberg03811012010-12-08 00:21:06 +0200651 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200652
653 rp.version = hdev->hci_ver;
654
Johan Hedberg03811012010-12-08 00:21:06 +0200655 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200656
657 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
658 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
659
660 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200661
662 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200663 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300665 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200666
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200667 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300668 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200669}
670
671static void mgmt_pending_free(struct pending_cmd *cmd)
672{
673 sock_put(cmd->sk);
674 kfree(cmd->param);
675 kfree(cmd);
676}
677
678static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300679 struct hci_dev *hdev, void *data,
680 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200681{
682 struct pending_cmd *cmd;
683
684 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
685 if (!cmd)
686 return NULL;
687
688 cmd->opcode = opcode;
689 cmd->index = hdev->id;
690
691 cmd->param = kmalloc(len, GFP_ATOMIC);
692 if (!cmd->param) {
693 kfree(cmd);
694 return NULL;
695 }
696
697 if (data)
698 memcpy(cmd->param, data, len);
699
700 cmd->sk = sk;
701 sock_hold(sk);
702
703 list_add(&cmd->list, &hdev->mgmt_pending);
704
705 return cmd;
706}
707
708static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300709 void (*cb)(struct pending_cmd *cmd, void *data),
710 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200711{
712 struct list_head *p, *n;
713
714 list_for_each_safe(p, n, &hdev->mgmt_pending) {
715 struct pending_cmd *cmd;
716
717 cmd = list_entry(p, struct pending_cmd, list);
718
719 if (opcode > 0 && cmd->opcode != opcode)
720 continue;
721
722 cb(cmd, data);
723 }
724}
725
726static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
727{
728 struct pending_cmd *cmd;
729
730 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
731 if (cmd->opcode == opcode)
732 return cmd;
733 }
734
735 return NULL;
736}
737
738static void mgmt_pending_remove(struct pending_cmd *cmd)
739{
740 list_del(&cmd->list);
741 mgmt_pending_free(cmd);
742}
743
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200744static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200745{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200746 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200747
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200748 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300749 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200750}
751
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200752static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300753 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200754{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300755 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200756 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200757 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200759 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200760
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300761 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200762
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100763 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
764 cancel_delayed_work(&hdev->power_off);
765
766 if (cp->val) {
767 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
768 mgmt_powered(hdev, 1);
769 goto failed;
770 }
771 }
772
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200773 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200774 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200775 goto failed;
776 }
777
778 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200779 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300780 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200781 goto failed;
782 }
783
784 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
785 if (!cmd) {
786 err = -ENOMEM;
787 goto failed;
788 }
789
790 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200791 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200792 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200793 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200794
795 err = 0;
796
797failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300798 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200799 return err;
800}
801
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300802static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
803 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200804{
805 struct sk_buff *skb;
806 struct mgmt_hdr *hdr;
807
808 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
809 if (!skb)
810 return -ENOMEM;
811
812 hdr = (void *) skb_put(skb, sizeof(*hdr));
813 hdr->opcode = cpu_to_le16(event);
814 if (hdev)
815 hdr->index = cpu_to_le16(hdev->id);
816 else
817 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
818 hdr->len = cpu_to_le16(data_len);
819
820 if (data)
821 memcpy(skb_put(skb, data_len), data, data_len);
822
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100823 /* Time stamp */
824 __net_timestamp(skb);
825
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200826 hci_send_to_control(skb, skip_sk);
827 kfree_skb(skb);
828
829 return 0;
830}
831
832static int new_settings(struct hci_dev *hdev, struct sock *skip)
833{
834 __le32 ev;
835
836 ev = cpu_to_le32(get_current_settings(hdev));
837
838 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
839}
840
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200841static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300842 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200843{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300844 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200845 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200846 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200847 u8 scan;
848 int err;
849
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200850 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200851
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100852 timeout = get_unaligned_le16(&cp->timeout);
853 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200854 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300855 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300857 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200858
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200859 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200860 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300861 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200862 goto failed;
863 }
864
865 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
866 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200867 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300868 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869 goto failed;
870 }
871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200873 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300874 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200875 goto failed;
876 }
877
878 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200879 bool changed = false;
880
881 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
882 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
883 changed = true;
884 }
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200887 if (err < 0)
888 goto failed;
889
890 if (changed)
891 err = new_settings(hdev, sk);
892
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200893 goto failed;
894 }
895
896 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100897 if (hdev->discov_timeout > 0) {
898 cancel_delayed_work(&hdev->discov_off);
899 hdev->discov_timeout = 0;
900 }
901
902 if (cp->val && timeout > 0) {
903 hdev->discov_timeout = timeout;
904 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
905 msecs_to_jiffies(hdev->discov_timeout * 1000));
906 }
907
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200908 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200909 goto failed;
910 }
911
912 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
913 if (!cmd) {
914 err = -ENOMEM;
915 goto failed;
916 }
917
918 scan = SCAN_PAGE;
919
920 if (cp->val)
921 scan |= SCAN_INQUIRY;
922 else
923 cancel_delayed_work(&hdev->discov_off);
924
925 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
926 if (err < 0)
927 mgmt_pending_remove(cmd);
928
Johan Hedberg03811012010-12-08 00:21:06 +0200929 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200930 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200931
932failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300933 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200934 return err;
935}
936
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200937static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300938 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200939{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300940 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200941 struct pending_cmd *cmd;
942 u8 scan;
943 int err;
944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200946
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200948
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200949 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200950 bool changed = false;
951
952 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
953 changed = true;
954
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200955 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200956 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200957 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200958 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
959 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
960 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200961
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200963 if (err < 0)
964 goto failed;
965
966 if (changed)
967 err = new_settings(hdev, sk);
968
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200969 goto failed;
970 }
971
972 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
973 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200974 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300975 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200976 goto failed;
977 }
978
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200980 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200981 goto failed;
982 }
983
984 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
985 if (!cmd) {
986 err = -ENOMEM;
987 goto failed;
988 }
989
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200990 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200991 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200992 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 scan = 0;
994
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200995 if (test_bit(HCI_ISCAN, &hdev->flags) &&
996 hdev->discov_timeout > 0)
997 cancel_delayed_work(&hdev->discov_off);
998 }
999
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1001 if (err < 0)
1002 mgmt_pending_remove(cmd);
1003
1004failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001005 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 return err;
1007}
1008
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001009static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001010 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001011{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001012 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001013 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001015 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001017 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001018
1019 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001020 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001021 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001022 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001024 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025 if (err < 0)
1026 goto failed;
1027
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001028 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
1030failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001031 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 return err;
1033}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001034
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001035static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1036 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001037{
1038 struct mgmt_mode *cp = data;
1039 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001040 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001041 int err;
1042
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001043 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001044
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001045 hci_dev_lock(hdev);
1046
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001047 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001048 bool changed = false;
1049
1050 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1051 &hdev->dev_flags)) {
1052 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1053 changed = true;
1054 }
1055
1056 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1057 if (err < 0)
1058 goto failed;
1059
1060 if (changed)
1061 err = new_settings(hdev, sk);
1062
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001063 goto failed;
1064 }
1065
1066 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001067 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001068 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001069 goto failed;
1070 }
1071
1072 val = !!cp->val;
1073
1074 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1075 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1076 goto failed;
1077 }
1078
1079 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1080 if (!cmd) {
1081 err = -ENOMEM;
1082 goto failed;
1083 }
1084
1085 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1086 if (err < 0) {
1087 mgmt_pending_remove(cmd);
1088 goto failed;
1089 }
1090
1091failed:
1092 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001093 return err;
1094}
1095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001096static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001097{
1098 struct mgmt_mode *cp = data;
1099 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001100 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001101 int err;
1102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001103 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001104
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001105 hci_dev_lock(hdev);
1106
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001107 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001108 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001109 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001110 goto failed;
1111 }
1112
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001113 val = !!cp->val;
1114
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001115 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001116 bool changed = false;
1117
1118 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1119 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1120 changed = true;
1121 }
1122
1123 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1124 if (err < 0)
1125 goto failed;
1126
1127 if (changed)
1128 err = new_settings(hdev, sk);
1129
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001130 goto failed;
1131 }
1132
1133 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001134 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1135 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001136 goto failed;
1137 }
1138
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001139 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1140 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1141 goto failed;
1142 }
1143
1144 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1145 if (!cmd) {
1146 err = -ENOMEM;
1147 goto failed;
1148 }
1149
1150 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1151 if (err < 0) {
1152 mgmt_pending_remove(cmd);
1153 goto failed;
1154 }
1155
1156failed:
1157 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001158 return err;
1159}
1160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001161static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001162{
1163 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001164
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001165 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001167 if (!enable_hs)
1168 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001169 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001170
1171 if (cp->val)
1172 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1173 else
1174 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001176 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177}
1178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001179static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001180{
1181 struct mgmt_mode *cp = data;
1182 struct hci_cp_write_le_host_supported hci_cp;
1183 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001184 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001185 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001188
Johan Hedberg1de028c2012-02-29 19:55:35 -08001189 hci_dev_lock(hdev);
1190
Johan Hedberg06199cf2012-02-22 16:37:11 +02001191 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001192 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001193 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001194 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001195 }
1196
1197 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001198 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001199
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001200 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001201 bool changed = false;
1202
1203 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1204 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1205 changed = true;
1206 }
1207
1208 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1209 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001210 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001211
1212 if (changed)
1213 err = new_settings(hdev, sk);
1214
Johan Hedberg1de028c2012-02-29 19:55:35 -08001215 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001216 }
1217
1218 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001219 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001220 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001221 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001222 }
1223
1224 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1225 if (!cmd) {
1226 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001227 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001228 }
1229
1230 memset(&hci_cp, 0, sizeof(hci_cp));
1231
1232 if (val) {
1233 hci_cp.le = val;
1234 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1235 }
1236
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001237 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1238 &hci_cp);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001239 if (err < 0) {
1240 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001241 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001242 }
1243
Johan Hedberg1de028c2012-02-29 19:55:35 -08001244unlock:
1245 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001246 return err;
1247}
1248
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001249static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001250{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001251 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001252 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001253 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001254 int err;
1255
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001256 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001257
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001258 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001260 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001261 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001262 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001263 goto failed;
1264 }
1265
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001266 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1267 if (!uuid) {
1268 err = -ENOMEM;
1269 goto failed;
1270 }
1271
1272 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001273 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001274
1275 list_add(&uuid->list, &hdev->uuids);
1276
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001277 err = update_class(hdev);
1278 if (err < 0)
1279 goto failed;
1280
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001281 err = update_eir(hdev);
1282 if (err < 0)
1283 goto failed;
1284
Johan Hedberg90e70452012-02-23 23:09:40 +02001285 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001286 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001287 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001288 goto failed;
1289 }
1290
1291 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1292 if (!cmd) {
1293 err = -ENOMEM;
1294 goto failed;
1295 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001296
1297failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001298 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001299 return err;
1300}
1301
Johan Hedberg24b78d02012-02-23 23:24:30 +02001302static bool enable_service_cache(struct hci_dev *hdev)
1303{
1304 if (!hdev_is_powered(hdev))
1305 return false;
1306
1307 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001308 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001309 return true;
1310 }
1311
1312 return false;
1313}
1314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001315static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1316 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001317{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001318 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001319 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001320 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001321 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 +02001322 int err, found;
1323
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001324 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001326 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001327
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001328 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001329 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001330 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001331 goto unlock;
1332 }
1333
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1335 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001336
Johan Hedberg24b78d02012-02-23 23:24:30 +02001337 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001338 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001339 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001340 goto unlock;
1341 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001342
Johan Hedberg9246a862012-02-23 21:33:16 +02001343 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001344 }
1345
1346 found = 0;
1347
1348 list_for_each_safe(p, n, &hdev->uuids) {
1349 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1350
1351 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1352 continue;
1353
1354 list_del(&match->list);
1355 found++;
1356 }
1357
1358 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001359 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001360 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001361 goto unlock;
1362 }
1363
Johan Hedberg9246a862012-02-23 21:33:16 +02001364update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001365 err = update_class(hdev);
1366 if (err < 0)
1367 goto unlock;
1368
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001369 err = update_eir(hdev);
1370 if (err < 0)
1371 goto unlock;
1372
Johan Hedberg90e70452012-02-23 23:09:40 +02001373 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001374 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001375 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001376 goto unlock;
1377 }
1378
1379 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1380 if (!cmd) {
1381 err = -ENOMEM;
1382 goto unlock;
1383 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001384
1385unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001386 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001387 return err;
1388}
1389
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001390static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001391 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001392{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001393 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001394 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001395 int err;
1396
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001397 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001398
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001399 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001400
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001401 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001402 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001403 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001404 goto unlock;
1405 }
1406
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001407 hdev->major_class = cp->major;
1408 hdev->minor_class = cp->minor;
1409
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001410 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001411 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001412 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001413 goto unlock;
1414 }
1415
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001416 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001417 hci_dev_unlock(hdev);
1418 cancel_delayed_work_sync(&hdev->service_cache);
1419 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001420 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001421 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001422
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001423 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001424 if (err < 0)
1425 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001426
Johan Hedberg90e70452012-02-23 23:09:40 +02001427 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001428 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001429 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001430 goto unlock;
1431 }
1432
1433 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1434 if (!cmd) {
1435 err = -ENOMEM;
1436 goto unlock;
1437 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001438
Johan Hedbergb5235a62012-02-21 14:32:24 +02001439unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001440 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001441 return err;
1442}
1443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001444static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1445 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001446{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001447 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001448 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001449 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001450
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001451 key_count = get_unaligned_le16(&cp->key_count);
1452
Johan Hedberg86742e12011-11-07 23:13:38 +02001453 expected_len = sizeof(*cp) + key_count *
1454 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001455 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001456 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001457 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001458 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001459 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001460 }
1461
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001462 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463 key_count);
1464
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001465 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001466
1467 hci_link_keys_clear(hdev);
1468
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001469 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001470
1471 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001472 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001473 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001474 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001475
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001476 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001477 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001478
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001479 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001480 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001481 }
1482
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001483 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001484
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001485 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001486
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001487 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001488}
1489
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001490static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001491 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001492{
1493 struct mgmt_ev_device_unpaired ev;
1494
1495 bacpy(&ev.addr.bdaddr, bdaddr);
1496 ev.addr.type = addr_type;
1497
1498 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001499 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001500}
1501
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001502static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001503 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001504{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001505 struct mgmt_cp_unpair_device *cp = data;
1506 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001507 struct hci_cp_disconnect dc;
1508 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001509 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001510 int err;
1511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001512 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001513
Johan Hedberga8a1d192011-11-10 15:54:38 +02001514 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001515 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1516 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001517
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001518 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001519 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001520 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001521 goto unlock;
1522 }
1523
Johan Hedberg124f6e32012-02-09 13:50:12 +02001524 if (cp->addr.type == MGMT_ADDR_BREDR)
1525 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1526 else
1527 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001528
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001529 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001530 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001531 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001532 goto unlock;
1533 }
1534
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001535 if (cp->disconnect) {
1536 if (cp->addr.type == MGMT_ADDR_BREDR)
1537 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1538 &cp->addr.bdaddr);
1539 else
1540 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1541 &cp->addr.bdaddr);
1542 } else {
1543 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001544 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001545
Johan Hedberga8a1d192011-11-10 15:54:38 +02001546 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001547 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001548 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001549 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001550 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001551 }
1552
Johan Hedberg124f6e32012-02-09 13:50:12 +02001553 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001554 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001555 if (!cmd) {
1556 err = -ENOMEM;
1557 goto unlock;
1558 }
1559
1560 put_unaligned_le16(conn->handle, &dc.handle);
1561 dc.reason = 0x13; /* Remote User Terminated Connection */
1562 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1563 if (err < 0)
1564 mgmt_pending_remove(cmd);
1565
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001566unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001567 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001568 return err;
1569}
1570
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001571static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001572 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001573{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001574 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001575 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001576 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001577 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001578 int err;
1579
1580 BT_DBG("");
1581
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001582 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001583
1584 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001585 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001586 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001587 goto failed;
1588 }
1589
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001590 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001591 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001592 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001593 goto failed;
1594 }
1595
Johan Hedberg88c3df12012-02-09 14:27:38 +02001596 if (cp->addr.type == MGMT_ADDR_BREDR)
1597 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1598 else
1599 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001600
Johan Hedberg8962ee72011-01-20 12:40:27 +02001601 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001602 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001603 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001604 goto failed;
1605 }
1606
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001607 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001608 if (!cmd) {
1609 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001610 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001611 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001612
1613 put_unaligned_le16(conn->handle, &dc.handle);
1614 dc.reason = 0x13; /* Remote User Terminated Connection */
1615
1616 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1617 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001618 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001619
1620failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001621 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001622 return err;
1623}
1624
Johan Hedberg48264f02011-11-09 13:58:58 +02001625static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001626{
1627 switch (link_type) {
1628 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001629 switch (addr_type) {
1630 case ADDR_LE_DEV_PUBLIC:
1631 return MGMT_ADDR_LE_PUBLIC;
1632 case ADDR_LE_DEV_RANDOM:
1633 return MGMT_ADDR_LE_RANDOM;
1634 default:
1635 return MGMT_ADDR_INVALID;
1636 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001637 case ACL_LINK:
1638 return MGMT_ADDR_BREDR;
1639 default:
1640 return MGMT_ADDR_INVALID;
1641 }
1642}
1643
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001644static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1645 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001646{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001647 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001648 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001649 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001650 int err;
1651 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001652
1653 BT_DBG("");
1654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001655 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001656
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001657 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001658 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001659 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001660 goto unlock;
1661 }
1662
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001663 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001664 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1665 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001666 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667 }
1668
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001669 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001670 rp = kmalloc(rp_len, GFP_ATOMIC);
1671 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001672 err = -ENOMEM;
1673 goto unlock;
1674 }
1675
Johan Hedberg2784eb42011-01-21 13:56:35 +02001676 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001677 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001678 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1679 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001680 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001681 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001682 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1683 continue;
1684 i++;
1685 }
1686
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001687 put_unaligned_le16(i, &rp->conn_count);
1688
Johan Hedberg4c659c32011-11-07 23:13:39 +02001689 /* Recalculate length in case of filtered SCO connections, etc */
1690 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001691
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001692 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001693 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001694
Johan Hedberga38528f2011-01-22 06:46:43 +02001695 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001696
1697unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001698 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001699 return err;
1700}
1701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001702static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001703 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001704{
1705 struct pending_cmd *cmd;
1706 int err;
1707
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001708 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001709 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001710 if (!cmd)
1711 return -ENOMEM;
1712
Johan Hedbergd8457692012-02-17 14:24:57 +02001713 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001715 if (err < 0)
1716 mgmt_pending_remove(cmd);
1717
1718 return err;
1719}
1720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001721static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001723{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001724 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001725 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001726 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001727 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001728 int err;
1729
1730 BT_DBG("");
1731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001732 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001733
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001734 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001736 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737 goto failed;
1738 }
1739
Johan Hedbergd8457692012-02-17 14:24:57 +02001740 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001741 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001742 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001743 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001744 goto failed;
1745 }
1746
1747 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001748 struct mgmt_cp_pin_code_neg_reply ncp;
1749
1750 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001751
1752 BT_ERR("PIN code is not 16 bytes long");
1753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001754 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001755 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001756 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001757 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001758
1759 goto failed;
1760 }
1761
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001762 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001763 if (!cmd) {
1764 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001765 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001766 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001767
Johan Hedbergd8457692012-02-17 14:24:57 +02001768 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001769 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001770 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771
1772 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1773 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001774 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001775
1776failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001777 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778 return err;
1779}
1780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001781static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001782 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001783{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001784 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785 int err;
1786
1787 BT_DBG("");
1788
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001789 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001790
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001791 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001792 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001793 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001794 goto failed;
1795 }
1796
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001797 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798
1799failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001800 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001801 return err;
1802}
1803
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001804static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1805 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001806{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001807 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001808
1809 BT_DBG("");
1810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001812
1813 hdev->io_capability = cp->io_capability;
1814
1815 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001816 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001818 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001820 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1821 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001822}
1823
Johan Hedberge9a416b2011-02-19 12:05:56 -03001824static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1825{
1826 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001827 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001828
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001829 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001830 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1831 continue;
1832
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833 if (cmd->user_data != conn)
1834 continue;
1835
1836 return cmd;
1837 }
1838
1839 return NULL;
1840}
1841
1842static void pairing_complete(struct pending_cmd *cmd, u8 status)
1843{
1844 struct mgmt_rp_pair_device rp;
1845 struct hci_conn *conn = cmd->user_data;
1846
Johan Hedbergba4e5642011-11-11 00:07:34 +02001847 bacpy(&rp.addr.bdaddr, &conn->dst);
1848 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001849
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001850 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001851 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001852
1853 /* So we don't get further callbacks for this connection */
1854 conn->connect_cfm_cb = NULL;
1855 conn->security_cfm_cb = NULL;
1856 conn->disconn_cfm_cb = NULL;
1857
1858 hci_conn_put(conn);
1859
Johan Hedberga664b5b2011-02-19 12:06:02 -03001860 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001861}
1862
1863static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1864{
1865 struct pending_cmd *cmd;
1866
1867 BT_DBG("status %u", status);
1868
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001869 cmd = find_pairing(conn);
1870 if (!cmd)
1871 BT_DBG("Unable to find a pending command");
1872 else
Johan Hedberge2113262012-02-18 15:20:03 +02001873 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874}
1875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001876static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001877 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001878{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001879 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001880 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001881 struct pending_cmd *cmd;
1882 u8 sec_level, auth_type;
1883 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001884 int err;
1885
1886 BT_DBG("");
1887
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001888 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001890 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001891 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001892 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001893 goto unlock;
1894 }
1895
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001896 sec_level = BT_SECURITY_MEDIUM;
1897 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001899 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001901
Johan Hedbergba4e5642011-11-11 00:07:34 +02001902 if (cp->addr.type == MGMT_ADDR_BREDR)
1903 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001904 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001905 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001906 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001907 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001908
Johan Hedberg1425acb2011-11-11 00:07:35 +02001909 memset(&rp, 0, sizeof(rp));
1910 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1911 rp.addr.type = cp->addr.type;
1912
Ville Tervo30e76272011-02-22 16:10:53 -03001913 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001915 MGMT_STATUS_CONNECT_FAILED, &rp,
1916 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001917 goto unlock;
1918 }
1919
1920 if (conn->connect_cfm_cb) {
1921 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001922 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001923 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001924 goto unlock;
1925 }
1926
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001927 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001928 if (!cmd) {
1929 err = -ENOMEM;
1930 hci_conn_put(conn);
1931 goto unlock;
1932 }
1933
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001934 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001935 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001936 conn->connect_cfm_cb = pairing_complete_cb;
1937
Johan Hedberge9a416b2011-02-19 12:05:56 -03001938 conn->security_cfm_cb = pairing_complete_cb;
1939 conn->disconn_cfm_cb = pairing_complete_cb;
1940 conn->io_capability = cp->io_cap;
1941 cmd->user_data = conn;
1942
1943 if (conn->state == BT_CONNECTED &&
1944 hci_conn_security(conn, sec_level, auth_type))
1945 pairing_complete(cmd, 0);
1946
1947 err = 0;
1948
1949unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001950 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 return err;
1952}
1953
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001954static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1955 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001956{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001957 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001958 struct pending_cmd *cmd;
1959 struct hci_conn *conn;
1960 int err;
1961
1962 BT_DBG("");
1963
Johan Hedberg28424702012-02-02 04:02:29 +02001964 hci_dev_lock(hdev);
1965
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001966 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001967 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001968 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001969 goto unlock;
1970 }
1971
Johan Hedberg28424702012-02-02 04:02:29 +02001972 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1973 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001974 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001975 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001976 goto unlock;
1977 }
1978
1979 conn = cmd->user_data;
1980
1981 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001983 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001984 goto unlock;
1985 }
1986
1987 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001990 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001991unlock:
1992 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02001993 return err;
1994}
1995
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001996static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001997 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
1998 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001999{
Johan Hedberga5c29682011-02-19 12:05:57 -03002000 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002001 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002002 int err;
2003
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002004 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002005
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002006 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002007 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002008 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002009 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002010 }
2011
Johan Hedberg272d90d2012-02-09 15:26:12 +02002012 if (type == MGMT_ADDR_BREDR)
2013 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2014 else
Brian Gix47c15e22011-11-16 13:53:14 -08002015 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002016
Johan Hedberg272d90d2012-02-09 15:26:12 +02002017 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002018 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002019 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002020 goto done;
2021 }
2022
2023 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002024 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002025 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002026
Brian Gix5fe57d92011-12-21 16:12:13 -08002027 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002028 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002029 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002030 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002031 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002032 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002033
Brian Gix47c15e22011-11-16 13:53:14 -08002034 goto done;
2035 }
2036
Brian Gix0df4c182011-11-16 13:53:13 -08002037 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002038 if (!cmd) {
2039 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002040 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002041 }
2042
Brian Gix0df4c182011-11-16 13:53:13 -08002043 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002044 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2045 struct hci_cp_user_passkey_reply cp;
2046
2047 bacpy(&cp.bdaddr, bdaddr);
2048 cp.passkey = passkey;
2049 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2050 } else
2051 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2052
Johan Hedberga664b5b2011-02-19 12:06:02 -03002053 if (err < 0)
2054 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002055
Brian Gix0df4c182011-11-16 13:53:13 -08002056done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002057 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002058 return err;
2059}
2060
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002061static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2062 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002063{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002064 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002065
2066 BT_DBG("");
2067
2068 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002069 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002070 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002071
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002072 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002073 MGMT_OP_USER_CONFIRM_REPLY,
2074 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002075}
2076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002077static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002078 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002079{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002080 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002081
2082 BT_DBG("");
2083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002084 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002085 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2086 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002087}
2088
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002089static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2090 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002091{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002092 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002093
2094 BT_DBG("");
2095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002096 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002097 MGMT_OP_USER_PASSKEY_REPLY,
2098 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002099}
2100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002101static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002102 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002103{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002104 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002105
2106 BT_DBG("");
2107
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002108 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002109 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2110 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002111}
2112
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002113static int update_name(struct hci_dev *hdev, const char *name)
2114{
2115 struct hci_cp_write_local_name cp;
2116
2117 memcpy(cp.name, name, sizeof(cp.name));
2118
2119 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2120}
2121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002122static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002123 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002124{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002125 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002126 struct pending_cmd *cmd;
2127 int err;
2128
2129 BT_DBG("");
2130
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002131 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002132
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002133 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002134
Johan Hedbergb5235a62012-02-21 14:32:24 +02002135 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002136 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002137
2138 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002139 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002140 if (err < 0)
2141 goto failed;
2142
2143 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002144 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002145
Johan Hedbergb5235a62012-02-21 14:32:24 +02002146 goto failed;
2147 }
2148
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002149 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002150 if (!cmd) {
2151 err = -ENOMEM;
2152 goto failed;
2153 }
2154
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002155 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002156 if (err < 0)
2157 mgmt_pending_remove(cmd);
2158
2159failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002160 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002161 return err;
2162}
2163
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002164static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002165 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002166{
Szymon Jancc35938b2011-03-22 13:12:21 +01002167 struct pending_cmd *cmd;
2168 int err;
2169
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002170 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002171
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002172 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002173
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002174 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002175 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002177 goto unlock;
2178 }
2179
2180 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002181 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002182 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002183 goto unlock;
2184 }
2185
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002186 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002187 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002188 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002189 goto unlock;
2190 }
2191
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002192 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002193 if (!cmd) {
2194 err = -ENOMEM;
2195 goto unlock;
2196 }
2197
2198 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2199 if (err < 0)
2200 mgmt_pending_remove(cmd);
2201
2202unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002203 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002204 return err;
2205}
2206
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002207static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002208 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002209{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002210 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002211 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002212 int err;
2213
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002214 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002217
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002218 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002219 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002220 MGMT_STATUS_NOT_POWERED, &cp->addr,
2221 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002222 goto unlock;
2223 }
2224
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002225 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002226 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002227 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002228 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002229 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002230 status = 0;
2231
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002234
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002235unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002236 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002237 return err;
2238}
2239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002240static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002241 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002242{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002243 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002244 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002245 int err;
2246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002247 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002250
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002251 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002252 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002253 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2254 MGMT_STATUS_NOT_POWERED, &cp->addr,
2255 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002256 goto unlock;
2257 }
2258
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002259 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002260 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002261 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002262 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002263 status = 0;
2264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002267
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002268unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002270 return err;
2271}
2272
Andre Guedes5e0452c2012-02-17 20:39:38 -03002273int mgmt_interleaved_discovery(struct hci_dev *hdev)
2274{
2275 int err;
2276
2277 BT_DBG("%s", hdev->name);
2278
2279 hci_dev_lock(hdev);
2280
2281 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2282 if (err < 0)
2283 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2284
2285 hci_dev_unlock(hdev);
2286
2287 return err;
2288}
2289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002290static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002291 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002292{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002293 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002294 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002295 int err;
2296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002297 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002298
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002299 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002300
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002301 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002302 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002303 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002304 goto failed;
2305 }
2306
Johan Hedbergff9ef572012-01-04 14:23:45 +02002307 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002308 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002309 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002310 goto failed;
2311 }
2312
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002313 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002314 if (!cmd) {
2315 err = -ENOMEM;
2316 goto failed;
2317 }
2318
Andre Guedes4aab14e2012-02-17 20:39:36 -03002319 hdev->discovery.type = cp->type;
2320
2321 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002322 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002323 if (lmp_bredr_capable(hdev))
2324 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2325 else
2326 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002327 break;
2328
2329 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002330 if (lmp_host_le_capable(hdev))
2331 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002332 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002333 else
2334 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002335 break;
2336
Andre Guedes5e0452c2012-02-17 20:39:38 -03002337 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002338 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2339 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340 LE_SCAN_WIN,
2341 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002342 else
2343 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002344 break;
2345
Andre Guedesf39799f2012-02-17 20:39:35 -03002346 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002347 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002348 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002349
Johan Hedberg14a53662011-04-27 10:29:56 -04002350 if (err < 0)
2351 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002352 else
2353 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002354
2355failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002356 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002357 return err;
2358}
2359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002361 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002362{
Johan Hedbergd9306502012-02-20 23:25:18 +02002363 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002364 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002365 struct hci_cp_remote_name_req_cancel cp;
2366 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002367 int err;
2368
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002369 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002370
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002371 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002372
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002373 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2376 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002377 goto unlock;
2378 }
2379
2380 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002381 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002382 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2383 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002384 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002385 }
2386
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002387 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002388 if (!cmd) {
2389 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002390 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002391 }
2392
Andre Guedes343f9352012-02-17 20:39:37 -03002393 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002394 err = hci_cancel_inquiry(hdev);
2395 if (err < 0)
2396 mgmt_pending_remove(cmd);
2397 else
2398 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2399 goto unlock;
2400 }
2401
2402 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2403 if (!e) {
2404 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002405 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002406 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002407 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2408 goto unlock;
2409 }
2410
2411 bacpy(&cp.bdaddr, &e->data.bdaddr);
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002412 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2413 &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002414 if (err < 0)
2415 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002416 else
2417 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002418
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002419unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002420 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002421 return err;
2422}
2423
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002424static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002425 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002426{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002427 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002428 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002429 int err;
2430
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002431 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002432
Johan Hedberg561aafb2012-01-04 13:31:59 +02002433 hci_dev_lock(hdev);
2434
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002435 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002436 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002437 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002438 goto failed;
2439 }
2440
Johan Hedberga198e7b2012-02-17 14:27:06 +02002441 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002442 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002443 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002444 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002445 goto failed;
2446 }
2447
2448 if (cp->name_known) {
2449 e->name_state = NAME_KNOWN;
2450 list_del(&e->list);
2451 } else {
2452 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002453 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002454 }
2455
2456 err = 0;
2457
2458failed:
2459 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002460 return err;
2461}
2462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002463static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002464 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002465{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002466 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002467 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002468 int err;
2469
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002470 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002471
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002472 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002473
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002474 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002475 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002476 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002477 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002478 status = 0;
2479
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002480 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002481 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002482
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002483 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002484
2485 return err;
2486}
2487
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002488static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002489 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002490{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002491 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002492 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002493 int err;
2494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002495 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002496
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002497 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002498
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002499 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002500 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002501 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002502 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002503 status = 0;
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002507
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002508 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002509
2510 return err;
2511}
2512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002513static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002514 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002515{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002516 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002517 struct hci_cp_write_page_scan_activity acp;
2518 u8 type;
2519 int err;
2520
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002521 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002522
Johan Hedberg5400c042012-02-21 16:40:33 +02002523 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002524 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002525 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002526
2527 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002528 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002529 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002530
2531 hci_dev_lock(hdev);
2532
Johan Hedbergf7c68692011-12-15 00:47:36 +02002533 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002534 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002535
2536 /* 22.5 msec page scan interval */
2537 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002538 } else {
2539 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002540
2541 /* default 1.28 sec page scan */
2542 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002543 }
2544
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002545 /* default 11.25 msec page scan window */
2546 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002547
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002548 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2549 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002550 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002551 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002552 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002553 goto done;
2554 }
2555
2556 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2557 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002558 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002559 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002560 goto done;
2561 }
2562
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002563 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002564 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002565done:
2566 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002567 return err;
2568}
2569
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002570static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002571 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002572{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002573 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2574 u16 key_count, expected_len;
2575 int i;
2576
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002577 key_count = get_unaligned_le16(&cp->key_count);
2578
2579 expected_len = sizeof(*cp) + key_count *
2580 sizeof(struct mgmt_ltk_info);
2581 if (expected_len != len) {
2582 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2583 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002584 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002586 }
2587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002588 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002589
2590 hci_dev_lock(hdev);
2591
2592 hci_smp_ltks_clear(hdev);
2593
2594 for (i = 0; i < key_count; i++) {
2595 struct mgmt_ltk_info *key = &cp->keys[i];
2596 u8 type;
2597
2598 if (key->master)
2599 type = HCI_SMP_LTK;
2600 else
2601 type = HCI_SMP_LTK_SLAVE;
2602
2603 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002604 type, 0, key->authenticated, key->val,
2605 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002606 }
2607
2608 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002609
2610 return 0;
2611}
2612
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002613struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002614 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2615 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002616 bool var_len;
2617 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002618} mgmt_handlers[] = {
2619 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002620 { read_version, false, MGMT_READ_VERSION_SIZE },
2621 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2622 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2623 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2624 { set_powered, false, MGMT_SETTING_SIZE },
2625 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2626 { set_connectable, false, MGMT_SETTING_SIZE },
2627 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2628 { set_pairable, false, MGMT_SETTING_SIZE },
2629 { set_link_security, false, MGMT_SETTING_SIZE },
2630 { set_ssp, false, MGMT_SETTING_SIZE },
2631 { set_hs, false, MGMT_SETTING_SIZE },
2632 { set_le, false, MGMT_SETTING_SIZE },
2633 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2634 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2635 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2636 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2637 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2638 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2639 { disconnect, false, MGMT_DISCONNECT_SIZE },
2640 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2641 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2642 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2643 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2644 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2645 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2646 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2647 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2648 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2649 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2650 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2651 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2652 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2653 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2654 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2655 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2656 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2657 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2658 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002659};
2660
2661
Johan Hedberg03811012010-12-08 00:21:06 +02002662int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2663{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002664 void *buf;
2665 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002666 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002667 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002668 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002669 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002670 int err;
2671
2672 BT_DBG("got %zu bytes", msglen);
2673
2674 if (msglen < sizeof(*hdr))
2675 return -EINVAL;
2676
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002677 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002678 if (!buf)
2679 return -ENOMEM;
2680
2681 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2682 err = -EFAULT;
2683 goto done;
2684 }
2685
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002686 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002687 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002688 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002689 len = get_unaligned_le16(&hdr->len);
2690
2691 if (len != msglen - sizeof(*hdr)) {
2692 err = -EINVAL;
2693 goto done;
2694 }
2695
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002696 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002697 hdev = hci_dev_get(index);
2698 if (!hdev) {
2699 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002701 goto done;
2702 }
2703 }
2704
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002705 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2706 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002707 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002708 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002709 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002710 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002711 }
2712
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002713 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2714 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2715 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002716 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002717 goto done;
2718 }
2719
Johan Hedbergbe22b542012-03-01 22:24:41 +02002720 handler = &mgmt_handlers[opcode];
2721
2722 if ((handler->var_len && len < handler->data_len) ||
2723 (!handler->var_len && len != handler->data_len)) {
2724 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002725 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002726 goto done;
2727 }
2728
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002729 if (hdev)
2730 mgmt_init_hdev(sk, hdev);
2731
2732 cp = buf + sizeof(*hdr);
2733
Johan Hedbergbe22b542012-03-01 22:24:41 +02002734 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002735 if (err < 0)
2736 goto done;
2737
Johan Hedberg03811012010-12-08 00:21:06 +02002738 err = msglen;
2739
2740done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002741 if (hdev)
2742 hci_dev_put(hdev);
2743
Johan Hedberg03811012010-12-08 00:21:06 +02002744 kfree(buf);
2745 return err;
2746}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002747
Johan Hedbergb24752f2011-11-03 14:40:33 +02002748static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2749{
2750 u8 *status = data;
2751
2752 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2753 mgmt_pending_remove(cmd);
2754}
2755
Johan Hedberg744cf192011-11-08 20:40:14 +02002756int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002757{
Johan Hedberg744cf192011-11-08 20:40:14 +02002758 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002759}
2760
Johan Hedberg744cf192011-11-08 20:40:14 +02002761int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002762{
Johan Hedberg5f159032012-03-02 03:13:19 +02002763 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002764
Johan Hedberg744cf192011-11-08 20:40:14 +02002765 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002766
Johan Hedberg744cf192011-11-08 20:40:14 +02002767 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002768}
2769
Johan Hedberg73f22f62010-12-29 16:00:25 +02002770struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002771 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002772 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002773 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002774};
2775
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002776static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002777{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002778 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002779
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002780 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002781
2782 list_del(&cmd->list);
2783
2784 if (match->sk == NULL) {
2785 match->sk = cmd->sk;
2786 sock_hold(match->sk);
2787 }
2788
2789 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002790}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002791
Johan Hedberg744cf192011-11-08 20:40:14 +02002792int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002793{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002794 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002795 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002796
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002797 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2798 return 0;
2799
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002800 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002801
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002802 if (powered) {
2803 u8 scan = 0;
2804
2805 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2806 scan |= SCAN_PAGE;
2807 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2808 scan |= SCAN_INQUIRY;
2809
2810 if (scan)
2811 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002812
2813 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002814 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002815 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002816 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002817 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002818 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002819 }
2820
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002821 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002822
2823 if (match.sk)
2824 sock_put(match.sk);
2825
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002826 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002827}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002828
Johan Hedberg744cf192011-11-08 20:40:14 +02002829int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002830{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002831 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002832 bool changed = false;
2833 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002834
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002835 if (discoverable) {
2836 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2837 changed = true;
2838 } else {
2839 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2840 changed = true;
2841 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002842
Johan Hedberged9b5f22012-02-21 20:47:06 +02002843 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002844 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002845
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002846 if (changed)
2847 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002848
Johan Hedberg73f22f62010-12-29 16:00:25 +02002849 if (match.sk)
2850 sock_put(match.sk);
2851
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002852 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002853}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002854
Johan Hedberg744cf192011-11-08 20:40:14 +02002855int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002856{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002857 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002858 bool changed = false;
2859 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002860
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002861 if (connectable) {
2862 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2863 changed = true;
2864 } else {
2865 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2866 changed = true;
2867 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002868
Johan Hedberged9b5f22012-02-21 20:47:06 +02002869 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002870 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002871
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002872 if (changed)
2873 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002874
2875 if (match.sk)
2876 sock_put(match.sk);
2877
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002878 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002879}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002880
Johan Hedberg744cf192011-11-08 20:40:14 +02002881int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002882{
Johan Hedbergca69b792011-11-11 18:10:00 +02002883 u8 mgmt_err = mgmt_status(status);
2884
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002885 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002886 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002887 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002888
2889 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002890 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002891 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002892
2893 return 0;
2894}
2895
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302896int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002897{
Johan Hedberg86742e12011-11-07 23:13:38 +02002898 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002899
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002900 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002901
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002902 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002903 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2904 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002905 ev.key.type = key->type;
2906 memcpy(ev.key.val, key->val, 16);
2907 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002908
Johan Hedberg744cf192011-11-08 20:40:14 +02002909 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002910}
Johan Hedbergf7520542011-01-20 12:34:39 +02002911
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002912int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2913{
2914 struct mgmt_ev_new_long_term_key ev;
2915
2916 memset(&ev, 0, sizeof(ev));
2917
2918 ev.store_hint = persistent;
2919 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2920 ev.key.addr.type = key->bdaddr_type;
2921 ev.key.authenticated = key->authenticated;
2922 ev.key.enc_size = key->enc_size;
2923 ev.key.ediv = key->ediv;
2924
2925 if (key->type == HCI_SMP_LTK)
2926 ev.key.master = 1;
2927
2928 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2929 memcpy(ev.key.val, key->val, sizeof(key->val));
2930
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002931 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2932 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002933}
2934
Johan Hedbergafc747a2012-01-15 18:11:07 +02002935int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002936 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2937 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002938{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002939 char buf[512];
2940 struct mgmt_ev_device_connected *ev = (void *) buf;
2941 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002942
Johan Hedbergb644ba32012-01-17 21:48:47 +02002943 bacpy(&ev->addr.bdaddr, bdaddr);
2944 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002945
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002946 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002947
Johan Hedbergb644ba32012-01-17 21:48:47 +02002948 if (name_len > 0)
2949 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002950 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002951
2952 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08002953 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002954 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002955
2956 put_unaligned_le16(eir_len, &ev->eir_len);
2957
2958 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002959 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002960}
2961
Johan Hedberg8962ee72011-01-20 12:40:27 +02002962static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2963{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002964 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002965 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002966 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002967
Johan Hedberg88c3df12012-02-09 14:27:38 +02002968 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2969 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002970
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002971 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002972 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002973
2974 *sk = cmd->sk;
2975 sock_hold(*sk);
2976
Johan Hedberga664b5b2011-02-19 12:06:02 -03002977 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002978}
2979
Johan Hedberg124f6e32012-02-09 13:50:12 +02002980static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002981{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002982 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002983 struct mgmt_cp_unpair_device *cp = cmd->param;
2984 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002985
2986 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002987 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2988 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002989
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002990 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2991
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002992 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002993
2994 mgmt_pending_remove(cmd);
2995}
2996
Johan Hedbergafc747a2012-01-15 18:11:07 +02002997int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002998 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002999{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003000 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003001 struct sock *sk = NULL;
3002 int err;
3003
Johan Hedberg744cf192011-11-08 20:40:14 +02003004 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003005
Johan Hedbergf7520542011-01-20 12:34:39 +02003006 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003007 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003008
Johan Hedbergafc747a2012-01-15 18:11:07 +02003009 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003010 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003011
3012 if (sk)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003014
Johan Hedberg124f6e32012-02-09 13:50:12 +02003015 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003016 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003017
Johan Hedberg8962ee72011-01-20 12:40:27 +02003018 return err;
3019}
3020
Johan Hedberg88c3df12012-02-09 14:27:38 +02003021int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003022 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003023{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003024 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003025 struct pending_cmd *cmd;
3026 int err;
3027
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003028 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003029 if (!cmd)
3030 return -ENOENT;
3031
Johan Hedberg88c3df12012-02-09 14:27:38 +02003032 bacpy(&rp.addr.bdaddr, bdaddr);
3033 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003034
Johan Hedberg88c3df12012-02-09 14:27:38 +02003035 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003037
Johan Hedberga664b5b2011-02-19 12:06:02 -03003038 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003040 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3041 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003042 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003043}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003044
Johan Hedberg48264f02011-11-09 13:58:58 +02003045int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003046 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003047{
3048 struct mgmt_ev_connect_failed ev;
3049
Johan Hedberg4c659c32011-11-07 23:13:39 +02003050 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003051 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003052 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003053
Johan Hedberg744cf192011-11-08 20:40:14 +02003054 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003055}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003056
Johan Hedberg744cf192011-11-08 20:40:14 +02003057int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003058{
3059 struct mgmt_ev_pin_code_request ev;
3060
Johan Hedbergd8457692012-02-17 14:24:57 +02003061 bacpy(&ev.addr.bdaddr, bdaddr);
3062 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003063 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003064
Johan Hedberg744cf192011-11-08 20:40:14 +02003065 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003066 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003067}
3068
Johan Hedberg744cf192011-11-08 20:40:14 +02003069int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003070 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003071{
3072 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003073 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003074 int err;
3075
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003076 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003077 if (!cmd)
3078 return -ENOENT;
3079
Johan Hedbergd8457692012-02-17 14:24:57 +02003080 bacpy(&rp.addr.bdaddr, bdaddr);
3081 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003082
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003083 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003084 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003085
Johan Hedberga664b5b2011-02-19 12:06:02 -03003086 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003087
3088 return err;
3089}
3090
Johan Hedberg744cf192011-11-08 20:40:14 +02003091int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003092 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003093{
3094 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003095 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003096 int err;
3097
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003098 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003099 if (!cmd)
3100 return -ENOENT;
3101
Johan Hedbergd8457692012-02-17 14:24:57 +02003102 bacpy(&rp.addr.bdaddr, bdaddr);
3103 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003104
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003105 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003106 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003107
Johan Hedberga664b5b2011-02-19 12:06:02 -03003108 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003109
3110 return err;
3111}
Johan Hedberga5c29682011-02-19 12:05:57 -03003112
Johan Hedberg744cf192011-11-08 20:40:14 +02003113int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003114 u8 link_type, u8 addr_type, __le32 value,
3115 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003116{
3117 struct mgmt_ev_user_confirm_request ev;
3118
Johan Hedberg744cf192011-11-08 20:40:14 +02003119 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003120
Johan Hedberg272d90d2012-02-09 15:26:12 +02003121 bacpy(&ev.addr.bdaddr, bdaddr);
3122 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003123 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003124 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003125
Johan Hedberg744cf192011-11-08 20:40:14 +02003126 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003128}
3129
Johan Hedberg272d90d2012-02-09 15:26:12 +02003130int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3131 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003132{
3133 struct mgmt_ev_user_passkey_request ev;
3134
3135 BT_DBG("%s", hdev->name);
3136
Johan Hedberg272d90d2012-02-09 15:26:12 +02003137 bacpy(&ev.addr.bdaddr, bdaddr);
3138 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003139
3140 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003141 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003142}
3143
Brian Gix0df4c182011-11-16 13:53:13 -08003144static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003145 u8 link_type, u8 addr_type, u8 status,
3146 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003147{
3148 struct pending_cmd *cmd;
3149 struct mgmt_rp_user_confirm_reply rp;
3150 int err;
3151
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003152 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003153 if (!cmd)
3154 return -ENOENT;
3155
Johan Hedberg272d90d2012-02-09 15:26:12 +02003156 bacpy(&rp.addr.bdaddr, bdaddr);
3157 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003158 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003159 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003160
Johan Hedberga664b5b2011-02-19 12:06:02 -03003161 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003162
3163 return err;
3164}
3165
Johan Hedberg744cf192011-11-08 20:40:14 +02003166int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003167 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003168{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003169 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003170 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003171}
3172
Johan Hedberg272d90d2012-02-09 15:26:12 +02003173int mgmt_user_confirm_neg_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_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003178}
Johan Hedberg2a611692011-02-19 12:06:00 -03003179
Brian Gix604086b2011-11-23 08:28:33 -08003180int mgmt_user_passkey_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)
Brian Gix604086b2011-11-23 08:28:33 -08003182{
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_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003185}
3186
Johan Hedberg272d90d2012-02-09 15:26:12 +02003187int mgmt_user_passkey_neg_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_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003192}
3193
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003194int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003195 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003196{
3197 struct mgmt_ev_auth_failed ev;
3198
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003199 bacpy(&ev.addr.bdaddr, bdaddr);
3200 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003201 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003202
Johan Hedberg744cf192011-11-08 20:40:14 +02003203 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003204}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003205
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003206int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3207{
3208 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003209 bool changed = false;
3210 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003211
3212 if (status) {
3213 u8 mgmt_err = mgmt_status(status);
3214 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003215 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003216 return 0;
3217 }
3218
Johan Hedberg47990ea2012-02-22 11:58:37 +02003219 if (test_bit(HCI_AUTH, &hdev->flags)) {
3220 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3221 changed = true;
3222 } else {
3223 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3224 changed = true;
3225 }
3226
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003227 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003228 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003229
Johan Hedberg47990ea2012-02-22 11:58:37 +02003230 if (changed)
3231 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003232
3233 if (match.sk)
3234 sock_put(match.sk);
3235
3236 return err;
3237}
3238
Johan Hedbergcacaf522012-02-21 00:52:42 +02003239static int clear_eir(struct hci_dev *hdev)
3240{
3241 struct hci_cp_write_eir cp;
3242
3243 if (!(hdev->features[6] & LMP_EXT_INQ))
3244 return 0;
3245
Johan Hedbergc80da272012-02-22 15:38:48 +02003246 memset(hdev->eir, 0, sizeof(hdev->eir));
3247
Johan Hedbergcacaf522012-02-21 00:52:42 +02003248 memset(&cp, 0, sizeof(cp));
3249
3250 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3251}
3252
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003253int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003254{
3255 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003256 bool changed = false;
3257 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003258
3259 if (status) {
3260 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003261
3262 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003263 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003264 err = new_settings(hdev, NULL);
3265
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003266 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3267 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003268
3269 return err;
3270 }
3271
3272 if (enable) {
3273 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3274 changed = true;
3275 } else {
3276 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3277 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003278 }
3279
3280 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3281
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003282 if (changed)
3283 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003284
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003285 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003286 sock_put(match.sk);
3287
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003288 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3289 update_eir(hdev);
3290 else
3291 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003292
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003293 return err;
3294}
3295
Johan Hedberg90e70452012-02-23 23:09:40 +02003296static void class_rsp(struct pending_cmd *cmd, void *data)
3297{
3298 struct cmd_lookup *match = data;
3299
3300 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003301 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003302
3303 list_del(&cmd->list);
3304
3305 if (match->sk == NULL) {
3306 match->sk = cmd->sk;
3307 sock_hold(match->sk);
3308 }
3309
3310 mgmt_pending_free(cmd);
3311}
3312
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003313int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003314 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003315{
Johan Hedberg90e70452012-02-23 23:09:40 +02003316 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3317 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003318
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003319 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3320
Johan Hedberg90e70452012-02-23 23:09:40 +02003321 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3322 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3323 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3324
3325 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003326 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3327 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003328
3329 if (match.sk)
3330 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003331
3332 return err;
3333}
3334
Johan Hedberg744cf192011-11-08 20:40:14 +02003335int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003336{
3337 struct pending_cmd *cmd;
3338 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003339 bool changed = false;
3340 int err = 0;
3341
3342 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3343 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3344 changed = true;
3345 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003346
3347 memset(&ev, 0, sizeof(ev));
3348 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003349 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003350
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003351 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003352 if (!cmd)
3353 goto send_event;
3354
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003355 /* Always assume that either the short or the complete name has
3356 * changed if there was a pending mgmt command */
3357 changed = true;
3358
Johan Hedbergb312b1612011-03-16 14:29:37 +02003359 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003360 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003361 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003362 goto failed;
3363 }
3364
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003365 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003366 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003367 if (err < 0)
3368 goto failed;
3369
3370send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003371 if (changed)
3372 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003373 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003374
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003375 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003376
3377failed:
3378 if (cmd)
3379 mgmt_pending_remove(cmd);
3380 return err;
3381}
Szymon Jancc35938b2011-03-22 13:12:21 +01003382
Johan Hedberg744cf192011-11-08 20:40:14 +02003383int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003384 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003385{
3386 struct pending_cmd *cmd;
3387 int err;
3388
Johan Hedberg744cf192011-11-08 20:40:14 +02003389 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003390
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003391 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003392 if (!cmd)
3393 return -ENOENT;
3394
3395 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003396 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3397 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003398 } else {
3399 struct mgmt_rp_read_local_oob_data rp;
3400
3401 memcpy(rp.hash, hash, sizeof(rp.hash));
3402 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3403
Johan Hedberg744cf192011-11-08 20:40:14 +02003404 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3406 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003407 }
3408
3409 mgmt_pending_remove(cmd);
3410
3411 return err;
3412}
Johan Hedberge17acd42011-03-30 23:57:16 +03003413
Johan Hedberg06199cf2012-02-22 16:37:11 +02003414int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3415{
3416 struct cmd_lookup match = { NULL, hdev };
3417 bool changed = false;
3418 int err = 0;
3419
3420 if (status) {
3421 u8 mgmt_err = mgmt_status(status);
3422
3423 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003424 &hdev->dev_flags))
3425 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003426
3427 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003428 cmd_status_rsp, &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003429
3430 return err;
3431 }
3432
3433 if (enable) {
3434 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3435 changed = true;
3436 } else {
3437 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3438 changed = true;
3439 }
3440
3441 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3442
3443 if (changed)
3444 err = new_settings(hdev, match.sk);
3445
3446 if (match.sk)
3447 sock_put(match.sk);
3448
3449 return err;
3450}
3451
Johan Hedberg48264f02011-11-09 13:58:58 +02003452int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003453 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3454 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003455{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003456 char buf[512];
3457 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003458 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003459
Johan Hedberg1dc06092012-01-15 21:01:23 +02003460 /* Leave 5 bytes for a potential CoD field */
3461 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003462 return -EINVAL;
3463
Johan Hedberg1dc06092012-01-15 21:01:23 +02003464 memset(buf, 0, sizeof(buf));
3465
Johan Hedberge319d2e2012-01-15 19:51:59 +02003466 bacpy(&ev->addr.bdaddr, bdaddr);
3467 ev->addr.type = link_to_mgmt(link_type, addr_type);
3468 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003469 if (cfm_name)
3470 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003471 if (!ssp)
3472 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003473
Johan Hedberg1dc06092012-01-15 21:01:23 +02003474 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003475 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003476
Johan Hedberg1dc06092012-01-15 21:01:23 +02003477 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3478 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003479 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003480
3481 put_unaligned_le16(eir_len, &ev->eir_len);
3482
3483 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003484
Johan Hedberge319d2e2012-01-15 19:51:59 +02003485 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003486}
Johan Hedberga88a9652011-03-30 13:18:12 +03003487
Johan Hedbergb644ba32012-01-17 21:48:47 +02003488int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003489 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003490{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003491 struct mgmt_ev_device_found *ev;
3492 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3493 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003494
Johan Hedbergb644ba32012-01-17 21:48:47 +02003495 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003496
Johan Hedbergb644ba32012-01-17 21:48:47 +02003497 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003498
Johan Hedbergb644ba32012-01-17 21:48:47 +02003499 bacpy(&ev->addr.bdaddr, bdaddr);
3500 ev->addr.type = link_to_mgmt(link_type, addr_type);
3501 ev->rssi = rssi;
3502
3503 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003504 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003505
3506 put_unaligned_le16(eir_len, &ev->eir_len);
3507
Johan Hedberg053c7e02012-02-04 00:06:00 +02003508 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003509 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003510}
Johan Hedberg314b2382011-04-27 10:29:57 -04003511
Andre Guedes7a135102011-11-09 17:14:25 -03003512int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003513{
3514 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003515 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003516 int err;
3517
Andre Guedes203159d2012-02-13 15:41:01 -03003518 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3519
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003520 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003521 if (!cmd)
3522 return -ENOENT;
3523
Johan Hedbergf808e162012-02-19 12:52:07 +02003524 type = hdev->discovery.type;
3525
3526 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003527 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003528 mgmt_pending_remove(cmd);
3529
3530 return err;
3531}
3532
Andre Guedese6d465c2011-11-09 17:14:26 -03003533int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3534{
3535 struct pending_cmd *cmd;
3536 int err;
3537
3538 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3539 if (!cmd)
3540 return -ENOENT;
3541
Johan Hedbergd9306502012-02-20 23:25:18 +02003542 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003543 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003544 mgmt_pending_remove(cmd);
3545
3546 return err;
3547}
Johan Hedberg314b2382011-04-27 10:29:57 -04003548
Johan Hedberg744cf192011-11-08 20:40:14 +02003549int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003550{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003551 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003552 struct pending_cmd *cmd;
3553
Andre Guedes343fb142011-11-22 17:14:19 -03003554 BT_DBG("%s discovering %u", hdev->name, discovering);
3555
Johan Hedberg164a6e72011-11-01 17:06:44 +02003556 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003557 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003558 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003559 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003560
3561 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003562 u8 type = hdev->discovery.type;
3563
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003564 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3565 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003566 mgmt_pending_remove(cmd);
3567 }
3568
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003569 memset(&ev, 0, sizeof(ev));
3570 ev.type = hdev->discovery.type;
3571 ev.discovering = discovering;
3572
3573 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003574}
Antti Julku5e762442011-08-25 16:48:02 +03003575
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003576int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003577{
3578 struct pending_cmd *cmd;
3579 struct mgmt_ev_device_blocked ev;
3580
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003581 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003582
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003583 bacpy(&ev.addr.bdaddr, bdaddr);
3584 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003585
Johan Hedberg744cf192011-11-08 20:40:14 +02003586 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003587 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003588}
3589
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003590int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003591{
3592 struct pending_cmd *cmd;
3593 struct mgmt_ev_device_unblocked ev;
3594
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003595 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003596
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003597 bacpy(&ev.addr.bdaddr, bdaddr);
3598 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003599
Johan Hedberg744cf192011-11-08 20:40:14 +02003600 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003601 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003602}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003603
3604module_param(enable_hs, bool, 0644);
3605MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3606
3607module_param(enable_le, bool, 0644);
3608MODULE_PARM_DESC(enable_le, "Enable Low Energy support");