blob: 991d5b6676747f55e42b805171ece9ecd441c745 [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;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010038
Johan Hedberg2da9c552012-02-17 14:39:28 +020039#define MGMT_VERSION 1
Marcel Holtmann053262d2012-03-27 18:49:02 +020040#define MGMT_REVISION 1
Johan Hedberg02d98122010-12-13 21:07:04 +020041
Johan Hedberge70bb2e2012-02-13 16:59:33 +020042static const u16 mgmt_commands[] = {
43 MGMT_OP_READ_INDEX_LIST,
44 MGMT_OP_READ_INFO,
45 MGMT_OP_SET_POWERED,
46 MGMT_OP_SET_DISCOVERABLE,
47 MGMT_OP_SET_CONNECTABLE,
48 MGMT_OP_SET_FAST_CONNECTABLE,
49 MGMT_OP_SET_PAIRABLE,
50 MGMT_OP_SET_LINK_SECURITY,
51 MGMT_OP_SET_SSP,
52 MGMT_OP_SET_HS,
53 MGMT_OP_SET_LE,
54 MGMT_OP_SET_DEV_CLASS,
55 MGMT_OP_SET_LOCAL_NAME,
56 MGMT_OP_ADD_UUID,
57 MGMT_OP_REMOVE_UUID,
58 MGMT_OP_LOAD_LINK_KEYS,
59 MGMT_OP_LOAD_LONG_TERM_KEYS,
60 MGMT_OP_DISCONNECT,
61 MGMT_OP_GET_CONNECTIONS,
62 MGMT_OP_PIN_CODE_REPLY,
63 MGMT_OP_PIN_CODE_NEG_REPLY,
64 MGMT_OP_SET_IO_CAPABILITY,
65 MGMT_OP_PAIR_DEVICE,
66 MGMT_OP_CANCEL_PAIR_DEVICE,
67 MGMT_OP_UNPAIR_DEVICE,
68 MGMT_OP_USER_CONFIRM_REPLY,
69 MGMT_OP_USER_CONFIRM_NEG_REPLY,
70 MGMT_OP_USER_PASSKEY_REPLY,
71 MGMT_OP_USER_PASSKEY_NEG_REPLY,
72 MGMT_OP_READ_LOCAL_OOB_DATA,
73 MGMT_OP_ADD_REMOTE_OOB_DATA,
74 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
75 MGMT_OP_START_DISCOVERY,
76 MGMT_OP_STOP_DISCOVERY,
77 MGMT_OP_CONFIRM_NAME,
78 MGMT_OP_BLOCK_DEVICE,
79 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070080 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020081};
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;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200227 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200228
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);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200257 ev->opcode = cpu_to_le16(cmd);
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;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200278 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200279
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;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200288 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
289 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200290 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200291 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
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200302 rp->num_commands = __constant_cpu_to_le16(num_commands);
303 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304
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
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200344 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345
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
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200351 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 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
Marcel Holtmann9d428202012-05-03 07:12:31 +0200386 if (hdev->features[4] & LMP_LE)
387 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389 return settings;
390}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392static u32 get_current_settings(struct hci_dev *hdev)
393{
394 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200395
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200396 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100397 settings |= MGMT_SETTING_POWERED;
398
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200399 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 settings |= MGMT_SETTING_CONNECTABLE;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_DISCOVERABLE;
404
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200405 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_PAIRABLE;
407
408 if (!(hdev->features[4] & LMP_NO_BREDR))
409 settings |= MGMT_SETTING_BREDR;
410
Johan Hedberg06199cf2012-02-22 16:37:11 +0200411 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200413
Johan Hedberg47990ea2012-02-22 11:58:37 +0200414 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200416
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200417 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200419
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200420 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
421 settings |= MGMT_SETTING_HS;
422
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200424}
425
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300426#define PNP_INFO_SVCLASS_ID 0x1200
427
428static u8 bluetooth_base_uuid[] = {
429 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
430 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
431};
432
433static u16 get_uuid16(u8 *uuid128)
434{
435 u32 val;
436 int i;
437
438 for (i = 0; i < 12; i++) {
439 if (bluetooth_base_uuid[i] != uuid128[i])
440 return 0;
441 }
442
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200443 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300444 if (val > 0xffff)
445 return 0;
446
447 return (u16) val;
448}
449
450static void create_eir(struct hci_dev *hdev, u8 *data)
451{
452 u8 *ptr = data;
453 u16 eir_len = 0;
454 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
455 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200456 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300457 size_t name_len;
458
459 name_len = strlen(hdev->dev_name);
460
461 if (name_len > 0) {
462 /* EIR Data type */
463 if (name_len > 48) {
464 name_len = 48;
465 ptr[1] = EIR_NAME_SHORT;
466 } else
467 ptr[1] = EIR_NAME_COMPLETE;
468
469 /* EIR Data length */
470 ptr[0] = name_len + 1;
471
472 memcpy(ptr + 2, hdev->dev_name, name_len);
473
474 eir_len += (name_len + 2);
475 ptr += (name_len + 2);
476 }
477
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700478 if (hdev->inq_tx_power) {
479 ptr[0] = 2;
480 ptr[1] = EIR_TX_POWER;
481 ptr[2] = (u8) hdev->inq_tx_power;
482
483 eir_len += 3;
484 ptr += 3;
485 }
486
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700487 if (hdev->devid_source > 0) {
488 ptr[0] = 9;
489 ptr[1] = EIR_DEVICE_ID;
490
491 put_unaligned_le16(hdev->devid_source, ptr + 2);
492 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
493 put_unaligned_le16(hdev->devid_product, ptr + 6);
494 put_unaligned_le16(hdev->devid_version, ptr + 8);
495
496 eir_len += 10;
497 ptr += 10;
498 }
499
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300500 memset(uuid16_list, 0, sizeof(uuid16_list));
501
502 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200503 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300504 u16 uuid16;
505
506 uuid16 = get_uuid16(uuid->uuid);
507 if (uuid16 == 0)
508 return;
509
510 if (uuid16 < 0x1100)
511 continue;
512
513 if (uuid16 == PNP_INFO_SVCLASS_ID)
514 continue;
515
516 /* Stop if not enough space to put next UUID */
517 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
518 truncated = 1;
519 break;
520 }
521
522 /* Check for duplicates */
523 for (i = 0; uuid16_list[i] != 0; i++)
524 if (uuid16_list[i] == uuid16)
525 break;
526
527 if (uuid16_list[i] == 0) {
528 uuid16_list[i] = uuid16;
529 eir_len += sizeof(u16);
530 }
531 }
532
533 if (uuid16_list[0] != 0) {
534 u8 *length = ptr;
535
536 /* EIR Data type */
537 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
538
539 ptr += 2;
540 eir_len += 2;
541
542 for (i = 0; uuid16_list[i] != 0; i++) {
543 *ptr++ = (uuid16_list[i] & 0x00ff);
544 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
545 }
546
547 /* EIR Data length */
548 *length = (i * sizeof(u16)) + 1;
549 }
550}
551
552static int update_eir(struct hci_dev *hdev)
553{
554 struct hci_cp_write_eir cp;
555
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200556 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200557 return 0;
558
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300559 if (!(hdev->features[6] & LMP_EXT_INQ))
560 return 0;
561
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200562 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300563 return 0;
564
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200565 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300566 return 0;
567
568 memset(&cp, 0, sizeof(cp));
569
570 create_eir(hdev, cp.data);
571
572 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
573 return 0;
574
575 memcpy(hdev->eir, cp.data, sizeof(cp.data));
576
577 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
578}
579
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200580static u8 get_service_classes(struct hci_dev *hdev)
581{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300582 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200583 u8 val = 0;
584
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300585 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200586 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200587
588 return val;
589}
590
591static int update_class(struct hci_dev *hdev)
592{
593 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200594 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595
596 BT_DBG("%s", hdev->name);
597
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200598 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200599 return 0;
600
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200601 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200602 return 0;
603
604 cod[0] = hdev->minor_class;
605 cod[1] = hdev->major_class;
606 cod[2] = get_service_classes(hdev);
607
608 if (memcmp(cod, hdev->dev_class, 3) == 0)
609 return 0;
610
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200611 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
612 if (err == 0)
613 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
614
615 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200616}
617
Johan Hedberg7d785252011-12-15 00:47:39 +0200618static void service_cache_off(struct work_struct *work)
619{
620 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300621 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200622
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200623 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200624 return;
625
626 hci_dev_lock(hdev);
627
628 update_eir(hdev);
629 update_class(hdev);
630
631 hci_dev_unlock(hdev);
632}
633
Johan Hedberg6a919082012-02-28 06:17:26 +0200634static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200635{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200636 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200637 return;
638
Johan Hedberg4f87da82012-03-02 19:55:56 +0200639 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200640
Johan Hedberg4f87da82012-03-02 19:55:56 +0200641 /* Non-mgmt controlled devices get this bit set
642 * implicitly so that pairing works for them, however
643 * for mgmt we require user-space to explicitly enable
644 * it
645 */
646 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200647}
648
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200649static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300650 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200651{
652 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200653
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200654 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200655
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300656 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200657
Johan Hedberg03811012010-12-08 00:21:06 +0200658 memset(&rp, 0, sizeof(rp));
659
Johan Hedberg03811012010-12-08 00:21:06 +0200660 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200661
662 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200663 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200664
665 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
666 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
667
668 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200669
670 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200671 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200672
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300673 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200674
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200675 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300676 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200677}
678
679static void mgmt_pending_free(struct pending_cmd *cmd)
680{
681 sock_put(cmd->sk);
682 kfree(cmd->param);
683 kfree(cmd);
684}
685
686static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300687 struct hci_dev *hdev, void *data,
688 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200689{
690 struct pending_cmd *cmd;
691
692 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
693 if (!cmd)
694 return NULL;
695
696 cmd->opcode = opcode;
697 cmd->index = hdev->id;
698
699 cmd->param = kmalloc(len, GFP_ATOMIC);
700 if (!cmd->param) {
701 kfree(cmd);
702 return NULL;
703 }
704
705 if (data)
706 memcpy(cmd->param, data, len);
707
708 cmd->sk = sk;
709 sock_hold(sk);
710
711 list_add(&cmd->list, &hdev->mgmt_pending);
712
713 return cmd;
714}
715
716static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300717 void (*cb)(struct pending_cmd *cmd, void *data),
718 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200719{
720 struct list_head *p, *n;
721
722 list_for_each_safe(p, n, &hdev->mgmt_pending) {
723 struct pending_cmd *cmd;
724
725 cmd = list_entry(p, struct pending_cmd, list);
726
727 if (opcode > 0 && cmd->opcode != opcode)
728 continue;
729
730 cb(cmd, data);
731 }
732}
733
734static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
735{
736 struct pending_cmd *cmd;
737
738 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
739 if (cmd->opcode == opcode)
740 return cmd;
741 }
742
743 return NULL;
744}
745
746static void mgmt_pending_remove(struct pending_cmd *cmd)
747{
748 list_del(&cmd->list);
749 mgmt_pending_free(cmd);
750}
751
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200752static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200753{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200754 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200755
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200756 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300757 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200758}
759
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200760static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300761 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200762{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300763 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200764 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200765 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200766
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200767 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200768
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300769 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200770
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100771 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
772 cancel_delayed_work(&hdev->power_off);
773
774 if (cp->val) {
775 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
776 mgmt_powered(hdev, 1);
777 goto failed;
778 }
779 }
780
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200781 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200782 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 goto failed;
784 }
785
786 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200787 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300788 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200789 goto failed;
790 }
791
792 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
793 if (!cmd) {
794 err = -ENOMEM;
795 goto failed;
796 }
797
798 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200799 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200800 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200801 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200802
803 err = 0;
804
805failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300806 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200807 return err;
808}
809
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300810static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
811 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200812{
813 struct sk_buff *skb;
814 struct mgmt_hdr *hdr;
815
816 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
817 if (!skb)
818 return -ENOMEM;
819
820 hdr = (void *) skb_put(skb, sizeof(*hdr));
821 hdr->opcode = cpu_to_le16(event);
822 if (hdev)
823 hdr->index = cpu_to_le16(hdev->id);
824 else
825 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
826 hdr->len = cpu_to_le16(data_len);
827
828 if (data)
829 memcpy(skb_put(skb, data_len), data, data_len);
830
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100831 /* Time stamp */
832 __net_timestamp(skb);
833
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200834 hci_send_to_control(skb, skip_sk);
835 kfree_skb(skb);
836
837 return 0;
838}
839
840static int new_settings(struct hci_dev *hdev, struct sock *skip)
841{
842 __le32 ev;
843
844 ev = cpu_to_le32(get_current_settings(hdev));
845
846 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
847}
848
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200849static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300850 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200851{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300852 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200853 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200854 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200855 u8 scan;
856 int err;
857
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200858 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200859
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700860 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100861 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200862 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300863 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200864
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300865 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200866
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200867 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200868 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300869 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200870 goto failed;
871 }
872
873 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
874 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200875 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300876 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200877 goto failed;
878 }
879
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200880 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200881 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300882 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200883 goto failed;
884 }
885
886 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200887 bool changed = false;
888
889 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
890 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
891 changed = true;
892 }
893
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200894 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200895 if (err < 0)
896 goto failed;
897
898 if (changed)
899 err = new_settings(hdev, sk);
900
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200901 goto failed;
902 }
903
904 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100905 if (hdev->discov_timeout > 0) {
906 cancel_delayed_work(&hdev->discov_off);
907 hdev->discov_timeout = 0;
908 }
909
910 if (cp->val && timeout > 0) {
911 hdev->discov_timeout = timeout;
912 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
913 msecs_to_jiffies(hdev->discov_timeout * 1000));
914 }
915
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200916 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200917 goto failed;
918 }
919
920 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
921 if (!cmd) {
922 err = -ENOMEM;
923 goto failed;
924 }
925
926 scan = SCAN_PAGE;
927
928 if (cp->val)
929 scan |= SCAN_INQUIRY;
930 else
931 cancel_delayed_work(&hdev->discov_off);
932
933 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
934 if (err < 0)
935 mgmt_pending_remove(cmd);
936
Johan Hedberg03811012010-12-08 00:21:06 +0200937 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200938 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200939
940failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300941 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200942 return err;
943}
944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300946 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200947{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300948 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200949 struct pending_cmd *cmd;
950 u8 scan;
951 int err;
952
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200953 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200954
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300955 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200956
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200957 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200958 bool changed = false;
959
960 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
961 changed = true;
962
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200963 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200964 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200965 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200966 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
967 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
968 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200969
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200971 if (err < 0)
972 goto failed;
973
974 if (changed)
975 err = new_settings(hdev, sk);
976
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200977 goto failed;
978 }
979
980 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
981 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200982 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300983 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 goto failed;
985 }
986
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200987 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200988 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200989 goto failed;
990 }
991
992 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
993 if (!cmd) {
994 err = -ENOMEM;
995 goto failed;
996 }
997
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200998 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200999 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001000 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 scan = 0;
1002
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001003 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1004 hdev->discov_timeout > 0)
1005 cancel_delayed_work(&hdev->discov_off);
1006 }
1007
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001008 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1009 if (err < 0)
1010 mgmt_pending_remove(cmd);
1011
1012failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001013 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014 return err;
1015}
1016
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001017static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001018 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001019{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001020 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001021 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001023 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001024
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001025 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001026
1027 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001028 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001030 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001032 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001033 if (err < 0)
1034 goto failed;
1035
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001036 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037
1038failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001039 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040 return err;
1041}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001042
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001043static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1044 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001045{
1046 struct mgmt_mode *cp = data;
1047 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001048 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001049 int err;
1050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001051 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001052
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001053 hci_dev_lock(hdev);
1054
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001055 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001056 bool changed = false;
1057
1058 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1059 &hdev->dev_flags)) {
1060 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1061 changed = true;
1062 }
1063
1064 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1065 if (err < 0)
1066 goto failed;
1067
1068 if (changed)
1069 err = new_settings(hdev, sk);
1070
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001071 goto failed;
1072 }
1073
1074 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001075 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001076 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001077 goto failed;
1078 }
1079
1080 val = !!cp->val;
1081
1082 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1083 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1084 goto failed;
1085 }
1086
1087 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1088 if (!cmd) {
1089 err = -ENOMEM;
1090 goto failed;
1091 }
1092
1093 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1094 if (err < 0) {
1095 mgmt_pending_remove(cmd);
1096 goto failed;
1097 }
1098
1099failed:
1100 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001101 return err;
1102}
1103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001104static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001105{
1106 struct mgmt_mode *cp = data;
1107 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001108 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001109 int err;
1110
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001111 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001112
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001113 hci_dev_lock(hdev);
1114
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001115 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001117 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001118 goto failed;
1119 }
1120
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001121 val = !!cp->val;
1122
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001123 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001124 bool changed = false;
1125
1126 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1127 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1128 changed = true;
1129 }
1130
1131 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1132 if (err < 0)
1133 goto failed;
1134
1135 if (changed)
1136 err = new_settings(hdev, sk);
1137
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001138 goto failed;
1139 }
1140
1141 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001142 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1143 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001144 goto failed;
1145 }
1146
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001147 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1148 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1149 goto failed;
1150 }
1151
1152 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1153 if (!cmd) {
1154 err = -ENOMEM;
1155 goto failed;
1156 }
1157
1158 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1159 if (err < 0) {
1160 mgmt_pending_remove(cmd);
1161 goto failed;
1162 }
1163
1164failed:
1165 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001166 return err;
1167}
1168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001169static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001170{
1171 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001173 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001175 if (!enable_hs)
1176 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001177 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001178
1179 if (cp->val)
1180 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1181 else
1182 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001184 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001185}
1186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001188{
1189 struct mgmt_mode *cp = data;
1190 struct hci_cp_write_le_host_supported hci_cp;
1191 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001192 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001193 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001196
Johan Hedberg1de028c2012-02-29 19:55:35 -08001197 hci_dev_lock(hdev);
1198
Marcel Holtmann9d428202012-05-03 07:12:31 +02001199 if (!(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001201 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001202 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001203 }
1204
1205 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001206 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001207
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001208 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001209 bool changed = false;
1210
1211 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1212 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1213 changed = true;
1214 }
1215
1216 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1217 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001218 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001219
1220 if (changed)
1221 err = new_settings(hdev, sk);
1222
Johan Hedberg1de028c2012-02-29 19:55:35 -08001223 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001224 }
1225
1226 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001227 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001228 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001229 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001230 }
1231
1232 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1233 if (!cmd) {
1234 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001235 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001236 }
1237
1238 memset(&hci_cp, 0, sizeof(hci_cp));
1239
1240 if (val) {
1241 hci_cp.le = val;
1242 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1243 }
1244
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001245 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1246 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301247 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001248 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001249
Johan Hedberg1de028c2012-02-29 19:55:35 -08001250unlock:
1251 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001252 return err;
1253}
1254
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001255static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001256{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001257 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001258 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001260 int err;
1261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001262 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001263
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001264 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001265
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001266 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001267 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001268 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001269 goto failed;
1270 }
1271
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1273 if (!uuid) {
1274 err = -ENOMEM;
1275 goto failed;
1276 }
1277
1278 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001279 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001280
1281 list_add(&uuid->list, &hdev->uuids);
1282
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001283 err = update_class(hdev);
1284 if (err < 0)
1285 goto failed;
1286
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001287 err = update_eir(hdev);
1288 if (err < 0)
1289 goto failed;
1290
Johan Hedberg90e70452012-02-23 23:09:40 +02001291 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001292 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001293 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001294 goto failed;
1295 }
1296
1297 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301298 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001299 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001300
1301failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001302 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001303 return err;
1304}
1305
Johan Hedberg24b78d02012-02-23 23:24:30 +02001306static bool enable_service_cache(struct hci_dev *hdev)
1307{
1308 if (!hdev_is_powered(hdev))
1309 return false;
1310
1311 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001312 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001313 return true;
1314 }
1315
1316 return false;
1317}
1318
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001319static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1320 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001321{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001322 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001323 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001324 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325 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 +02001326 int err, found;
1327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001328 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001329
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001330 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001331
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001332 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001333 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001334 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001335 goto unlock;
1336 }
1337
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1339 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001340
Johan Hedberg24b78d02012-02-23 23:24:30 +02001341 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001344 goto unlock;
1345 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001346
Johan Hedberg9246a862012-02-23 21:33:16 +02001347 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001348 }
1349
1350 found = 0;
1351
1352 list_for_each_safe(p, n, &hdev->uuids) {
1353 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1354
1355 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1356 continue;
1357
1358 list_del(&match->list);
1359 found++;
1360 }
1361
1362 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001363 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001364 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001365 goto unlock;
1366 }
1367
Johan Hedberg9246a862012-02-23 21:33:16 +02001368update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001369 err = update_class(hdev);
1370 if (err < 0)
1371 goto unlock;
1372
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001373 err = update_eir(hdev);
1374 if (err < 0)
1375 goto unlock;
1376
Johan Hedberg90e70452012-02-23 23:09:40 +02001377 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001378 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001379 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001380 goto unlock;
1381 }
1382
1383 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301384 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001385 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001386
1387unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001388 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001389 return err;
1390}
1391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001393 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001394{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001395 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001396 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001397 int err;
1398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001399 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001400
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001401 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001402
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001403 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001404 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001405 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001406 goto unlock;
1407 }
1408
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001409 hdev->major_class = cp->major;
1410 hdev->minor_class = cp->minor;
1411
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001412 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001413 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001414 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001415 goto unlock;
1416 }
1417
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001418 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001419 hci_dev_unlock(hdev);
1420 cancel_delayed_work_sync(&hdev->service_cache);
1421 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001422 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001423 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001424
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001425 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001426 if (err < 0)
1427 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001428
Johan Hedberg90e70452012-02-23 23:09:40 +02001429 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001430 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001431 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001432 goto unlock;
1433 }
1434
1435 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301436 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001437 err = -ENOMEM;
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
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001451 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001452
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
Andre Guedes591f47f2012-04-24 21:02:49 -03001524 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001525 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) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001536 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001537 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
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001560 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001561 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
Andre Guedes591f47f2012-04-24 21:02:49 -03001596 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg88c3df12012-02-09 14:27:38 +02001597 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
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001613 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001614 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
Andre Guedes57c14772012-04-24 21:02:50 -03001625static u8 link_to_bdaddr(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:
Andre Guedes591f47f2012-04-24 21:02:49 -03001631 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001632
Johan Hedberg48264f02011-11-09 13:58:58 +02001633 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001634 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001635 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001636 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001637
Johan Hedberg4c659c32011-11-07 23:13:39 +02001638 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001639 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001640 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001641 }
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);
Andre Guedes57c14772012-04-24 21:02:50 -03001681 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001682 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001683 continue;
1684 i++;
1685 }
1686
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001687 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001688
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);
Andre Guedes57c14772012-04-24 21:02:50 -03001848 rp.addr.type = link_to_bdaddr(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
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301876static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1877{
1878 struct pending_cmd *cmd;
1879
1880 BT_DBG("status %u", status);
1881
1882 if (!status)
1883 return;
1884
1885 cmd = find_pairing(conn);
1886 if (!cmd)
1887 BT_DBG("Unable to find a pending command");
1888 else
1889 pairing_complete(cmd, mgmt_status(status));
1890}
1891
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001892static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001893 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001895 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001896 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897 struct pending_cmd *cmd;
1898 u8 sec_level, auth_type;
1899 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 int err;
1901
1902 BT_DBG("");
1903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001904 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001905
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001906 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001907 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001908 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001909 goto unlock;
1910 }
1911
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001912 sec_level = BT_SECURITY_MEDIUM;
1913 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001915 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001916 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001917
Andre Guedes591f47f2012-04-24 21:02:49 -03001918 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001919 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1920 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001921 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001922 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1923 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001924
Johan Hedberg1425acb2011-11-11 00:07:35 +02001925 memset(&rp, 0, sizeof(rp));
1926 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1927 rp.addr.type = cp->addr.type;
1928
Ville Tervo30e76272011-02-22 16:10:53 -03001929 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001930 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001931 MGMT_STATUS_CONNECT_FAILED, &rp,
1932 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001933 goto unlock;
1934 }
1935
1936 if (conn->connect_cfm_cb) {
1937 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001938 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001939 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940 goto unlock;
1941 }
1942
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001943 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001944 if (!cmd) {
1945 err = -ENOMEM;
1946 hci_conn_put(conn);
1947 goto unlock;
1948 }
1949
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001950 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001951 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001952 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301953 else
1954 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001955
Johan Hedberge9a416b2011-02-19 12:05:56 -03001956 conn->security_cfm_cb = pairing_complete_cb;
1957 conn->disconn_cfm_cb = pairing_complete_cb;
1958 conn->io_capability = cp->io_cap;
1959 cmd->user_data = conn;
1960
1961 if (conn->state == BT_CONNECTED &&
1962 hci_conn_security(conn, sec_level, auth_type))
1963 pairing_complete(cmd, 0);
1964
1965 err = 0;
1966
1967unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001968 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001969 return err;
1970}
1971
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001972static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1973 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001974{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001975 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001976 struct pending_cmd *cmd;
1977 struct hci_conn *conn;
1978 int err;
1979
1980 BT_DBG("");
1981
Johan Hedberg28424702012-02-02 04:02:29 +02001982 hci_dev_lock(hdev);
1983
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001984 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001985 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001986 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001987 goto unlock;
1988 }
1989
Johan Hedberg28424702012-02-02 04:02:29 +02001990 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1991 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001992 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001993 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001994 goto unlock;
1995 }
1996
1997 conn = cmd->user_data;
1998
1999 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002000 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002001 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002002 goto unlock;
2003 }
2004
2005 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2006
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002007 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002008 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002009unlock:
2010 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002011 return err;
2012}
2013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2016 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002017{
Johan Hedberga5c29682011-02-19 12:05:57 -03002018 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002019 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002020 int err;
2021
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002022 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002023
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002024 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002025 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002026 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002027 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002028 }
2029
Andre Guedes591f47f2012-04-24 21:02:49 -03002030 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002031 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2032 else
Brian Gix47c15e22011-11-16 13:53:14 -08002033 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002034
Johan Hedberg272d90d2012-02-09 15:26:12 +02002035 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002036 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002037 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002038 goto done;
2039 }
2040
Andre Guedes591f47f2012-04-24 21:02:49 -03002041 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002042 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002043 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002044
Brian Gix5fe57d92011-12-21 16:12:13 -08002045 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002046 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002047 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002048 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002049 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002050 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002051
Brian Gix47c15e22011-11-16 13:53:14 -08002052 goto done;
2053 }
2054
Brian Gix0df4c182011-11-16 13:53:13 -08002055 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002056 if (!cmd) {
2057 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002058 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002059 }
2060
Brian Gix0df4c182011-11-16 13:53:13 -08002061 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002062 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2063 struct hci_cp_user_passkey_reply cp;
2064
2065 bacpy(&cp.bdaddr, bdaddr);
2066 cp.passkey = passkey;
2067 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2068 } else
2069 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2070
Johan Hedberga664b5b2011-02-19 12:06:02 -03002071 if (err < 0)
2072 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002073
Brian Gix0df4c182011-11-16 13:53:13 -08002074done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002075 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002076 return err;
2077}
2078
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2080 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002081{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002082 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002083
2084 BT_DBG("");
2085
2086 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002087 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002088 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002090 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002091 MGMT_OP_USER_CONFIRM_REPLY,
2092 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002093}
2094
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002095static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002096 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002097{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002098 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002099
2100 BT_DBG("");
2101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002102 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002103 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2104 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002105}
2106
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002107static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2108 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002109{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002110 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002111
2112 BT_DBG("");
2113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 MGMT_OP_USER_PASSKEY_REPLY,
2116 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002117}
2118
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002119static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002120 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002121{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002122 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002123
2124 BT_DBG("");
2125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002126 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002127 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2128 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002129}
2130
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002131static int update_name(struct hci_dev *hdev, const char *name)
2132{
2133 struct hci_cp_write_local_name cp;
2134
2135 memcpy(cp.name, name, sizeof(cp.name));
2136
2137 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2138}
2139
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002140static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002141 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002142{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002143 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002144 struct pending_cmd *cmd;
2145 int err;
2146
2147 BT_DBG("");
2148
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002149 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002150
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002151 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002152
Johan Hedbergb5235a62012-02-21 14:32:24 +02002153 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002154 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002155
2156 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002158 if (err < 0)
2159 goto failed;
2160
2161 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002162 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002163
Johan Hedbergb5235a62012-02-21 14:32:24 +02002164 goto failed;
2165 }
2166
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002167 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002168 if (!cmd) {
2169 err = -ENOMEM;
2170 goto failed;
2171 }
2172
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002173 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002174 if (err < 0)
2175 mgmt_pending_remove(cmd);
2176
2177failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002178 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002179 return err;
2180}
2181
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002182static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002183 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002184{
Szymon Jancc35938b2011-03-22 13:12:21 +01002185 struct pending_cmd *cmd;
2186 int err;
2187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002189
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002190 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002191
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002192 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002194 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002195 goto unlock;
2196 }
2197
2198 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002199 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002200 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002201 goto unlock;
2202 }
2203
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002204 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002205 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002206 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002207 goto unlock;
2208 }
2209
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002210 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002211 if (!cmd) {
2212 err = -ENOMEM;
2213 goto unlock;
2214 }
2215
2216 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2217 if (err < 0)
2218 mgmt_pending_remove(cmd);
2219
2220unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002221 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002222 return err;
2223}
2224
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002225static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002226 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002227{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002228 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002229 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002230 int err;
2231
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002233
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002234 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002235
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002236 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002237 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002238 MGMT_STATUS_NOT_POWERED, &cp->addr,
2239 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002240 goto unlock;
2241 }
2242
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002243 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002244 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002245 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002246 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002247 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002248 status = 0;
2249
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002250 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002251 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002252
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002253unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002254 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002255 return err;
2256}
2257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002258static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002259 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002260{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002261 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002262 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002263 int err;
2264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002266
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002267 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002268
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002269 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002270 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002271 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2272 MGMT_STATUS_NOT_POWERED, &cp->addr,
2273 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002274 goto unlock;
2275 }
2276
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002277 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002278 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002279 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002280 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002281 status = 0;
2282
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002283 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002284 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002285
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002286unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002287 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002288 return err;
2289}
2290
Andre Guedes5e0452c2012-02-17 20:39:38 -03002291int mgmt_interleaved_discovery(struct hci_dev *hdev)
2292{
2293 int err;
2294
2295 BT_DBG("%s", hdev->name);
2296
2297 hci_dev_lock(hdev);
2298
2299 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2300 if (err < 0)
2301 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2302
2303 hci_dev_unlock(hdev);
2304
2305 return err;
2306}
2307
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002308static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002309 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002310{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002311 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002312 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002313 int err;
2314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002316
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002317 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002318
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002319 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002320 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002321 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002322 goto failed;
2323 }
2324
Andre Guedes642be6c2012-03-21 00:03:37 -03002325 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2326 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2327 MGMT_STATUS_BUSY);
2328 goto failed;
2329 }
2330
Johan Hedbergff9ef572012-01-04 14:23:45 +02002331 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002332 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002333 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002334 goto failed;
2335 }
2336
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002337 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002338 if (!cmd) {
2339 err = -ENOMEM;
2340 goto failed;
2341 }
2342
Andre Guedes4aab14e2012-02-17 20:39:36 -03002343 hdev->discovery.type = cp->type;
2344
2345 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002346 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002347 if (lmp_bredr_capable(hdev))
2348 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2349 else
2350 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002351 break;
2352
2353 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002354 if (lmp_host_le_capable(hdev))
2355 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002356 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002357 else
2358 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002359 break;
2360
Andre Guedes5e0452c2012-02-17 20:39:38 -03002361 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002362 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2363 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002364 LE_SCAN_WIN,
2365 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002366 else
2367 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002368 break;
2369
Andre Guedesf39799f2012-02-17 20:39:35 -03002370 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002371 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002372 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002373
Johan Hedberg14a53662011-04-27 10:29:56 -04002374 if (err < 0)
2375 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002376 else
2377 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002378
2379failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002380 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 return err;
2382}
2383
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002384static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002385 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002386{
Johan Hedbergd9306502012-02-20 23:25:18 +02002387 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002388 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002389 struct hci_cp_remote_name_req_cancel cp;
2390 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002391 int err;
2392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002393 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002394
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002395 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002396
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002397 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002398 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002399 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2400 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002401 goto unlock;
2402 }
2403
2404 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002405 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002406 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2407 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002408 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002409 }
2410
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002411 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002412 if (!cmd) {
2413 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002414 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002415 }
2416
Andre Guedese0d9727e2012-03-20 15:15:36 -03002417 switch (hdev->discovery.state) {
2418 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002419 if (test_bit(HCI_INQUIRY, &hdev->flags))
2420 err = hci_cancel_inquiry(hdev);
2421 else
2422 err = hci_cancel_le_scan(hdev);
2423
Andre Guedese0d9727e2012-03-20 15:15:36 -03002424 break;
2425
2426 case DISCOVERY_RESOLVING:
2427 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
2428 NAME_PENDING);
2429 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002430 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002431 err = cmd_complete(sk, hdev->id,
2432 MGMT_OP_STOP_DISCOVERY, 0,
2433 &mgmt_cp->type,
2434 sizeof(mgmt_cp->type));
2435 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2436 goto unlock;
2437 }
2438
2439 bacpy(&cp.bdaddr, &e->data.bdaddr);
2440 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2441 sizeof(cp), &cp);
2442
2443 break;
2444
2445 default:
2446 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2447 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002448 }
2449
Johan Hedberg14a53662011-04-27 10:29:56 -04002450 if (err < 0)
2451 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002452 else
2453 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002454
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002455unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002456 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002457 return err;
2458}
2459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002460static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002461 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002462{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002463 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002464 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002465 int err;
2466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002467 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002468
Johan Hedberg561aafb2012-01-04 13:31:59 +02002469 hci_dev_lock(hdev);
2470
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002471 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002472 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002474 goto failed;
2475 }
2476
Johan Hedberga198e7b2012-02-17 14:27:06 +02002477 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002478 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002481 goto failed;
2482 }
2483
2484 if (cp->name_known) {
2485 e->name_state = NAME_KNOWN;
2486 list_del(&e->list);
2487 } else {
2488 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002489 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002490 }
2491
2492 err = 0;
2493
2494failed:
2495 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002496 return err;
2497}
2498
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002499static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002500 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002501{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002502 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002503 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002504 int err;
2505
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002506 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002507
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002508 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002509
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002510 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002511 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002512 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002513 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002514 status = 0;
2515
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002516 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002517 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002518
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002519 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002520
2521 return err;
2522}
2523
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002524static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002525 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002526{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002527 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002528 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002529 int err;
2530
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002531 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002532
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002533 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002534
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002535 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002536 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002537 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002538 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002539 status = 0;
2540
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002541 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002542 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002543
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002544 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002545
2546 return err;
2547}
2548
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002549static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2550 u16 len)
2551{
2552 struct mgmt_cp_set_device_id *cp = data;
2553 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002554 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002555
2556 BT_DBG("%s", hdev->name);
2557
Szymon Jancc72d4b82012-03-16 16:02:57 +01002558 source = __le16_to_cpu(cp->source);
2559
2560 if (source > 0x0002)
2561 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2562 MGMT_STATUS_INVALID_PARAMS);
2563
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002564 hci_dev_lock(hdev);
2565
Szymon Jancc72d4b82012-03-16 16:02:57 +01002566 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002567 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2568 hdev->devid_product = __le16_to_cpu(cp->product);
2569 hdev->devid_version = __le16_to_cpu(cp->version);
2570
2571 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2572
2573 update_eir(hdev);
2574
2575 hci_dev_unlock(hdev);
2576
2577 return err;
2578}
2579
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002580static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002581 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002582{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002583 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002584 struct hci_cp_write_page_scan_activity acp;
2585 u8 type;
2586 int err;
2587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002588 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002589
Johan Hedberg5400c042012-02-21 16:40:33 +02002590 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002591 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002592 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002593
2594 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002595 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002596 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002597
2598 hci_dev_lock(hdev);
2599
Johan Hedbergf7c68692011-12-15 00:47:36 +02002600 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002601 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002602
2603 /* 22.5 msec page scan interval */
2604 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002605 } else {
2606 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002607
2608 /* default 1.28 sec page scan */
2609 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002610 }
2611
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002612 /* default 11.25 msec page scan window */
2613 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002614
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002615 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2616 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002617 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002619 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002620 goto done;
2621 }
2622
2623 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2624 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002625 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002626 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002627 goto done;
2628 }
2629
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002630 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002631 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002632done:
2633 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002634 return err;
2635}
2636
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002639{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002640 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2641 u16 key_count, expected_len;
2642 int i;
2643
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002644 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002645
2646 expected_len = sizeof(*cp) + key_count *
2647 sizeof(struct mgmt_ltk_info);
2648 if (expected_len != len) {
2649 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2650 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002651 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002652 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002653 }
2654
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002655 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002656
2657 hci_dev_lock(hdev);
2658
2659 hci_smp_ltks_clear(hdev);
2660
2661 for (i = 0; i < key_count; i++) {
2662 struct mgmt_ltk_info *key = &cp->keys[i];
2663 u8 type;
2664
2665 if (key->master)
2666 type = HCI_SMP_LTK;
2667 else
2668 type = HCI_SMP_LTK_SLAVE;
2669
Hemant Gupta4596fde2012-04-16 14:57:40 +05302670 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002671 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002672 type, 0, key->authenticated, key->val,
2673 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002674 }
2675
2676 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002677
2678 return 0;
2679}
2680
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002681static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002682 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2683 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002684 bool var_len;
2685 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002686} mgmt_handlers[] = {
2687 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002688 { read_version, false, MGMT_READ_VERSION_SIZE },
2689 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2690 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2691 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2692 { set_powered, false, MGMT_SETTING_SIZE },
2693 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2694 { set_connectable, false, MGMT_SETTING_SIZE },
2695 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2696 { set_pairable, false, MGMT_SETTING_SIZE },
2697 { set_link_security, false, MGMT_SETTING_SIZE },
2698 { set_ssp, false, MGMT_SETTING_SIZE },
2699 { set_hs, false, MGMT_SETTING_SIZE },
2700 { set_le, false, MGMT_SETTING_SIZE },
2701 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2702 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2703 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2704 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2705 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2706 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2707 { disconnect, false, MGMT_DISCONNECT_SIZE },
2708 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2709 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2710 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2711 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2712 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2713 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2714 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2715 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2716 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2717 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2718 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2719 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2720 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2721 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2722 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2723 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2724 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2725 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2726 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002727 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002728};
2729
2730
Johan Hedberg03811012010-12-08 00:21:06 +02002731int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2732{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002733 void *buf;
2734 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002735 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002736 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002737 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002738 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002739 int err;
2740
2741 BT_DBG("got %zu bytes", msglen);
2742
2743 if (msglen < sizeof(*hdr))
2744 return -EINVAL;
2745
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002746 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002747 if (!buf)
2748 return -ENOMEM;
2749
2750 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2751 err = -EFAULT;
2752 goto done;
2753 }
2754
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002755 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002756 opcode = __le16_to_cpu(hdr->opcode);
2757 index = __le16_to_cpu(hdr->index);
2758 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002759
2760 if (len != msglen - sizeof(*hdr)) {
2761 err = -EINVAL;
2762 goto done;
2763 }
2764
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002765 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002766 hdev = hci_dev_get(index);
2767 if (!hdev) {
2768 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002769 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002770 goto done;
2771 }
2772 }
2773
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002774 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2775 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002776 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002777 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002778 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002779 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002780 }
2781
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002782 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2783 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2784 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002785 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002786 goto done;
2787 }
2788
Johan Hedbergbe22b542012-03-01 22:24:41 +02002789 handler = &mgmt_handlers[opcode];
2790
2791 if ((handler->var_len && len < handler->data_len) ||
2792 (!handler->var_len && len != handler->data_len)) {
2793 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002794 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002795 goto done;
2796 }
2797
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002798 if (hdev)
2799 mgmt_init_hdev(sk, hdev);
2800
2801 cp = buf + sizeof(*hdr);
2802
Johan Hedbergbe22b542012-03-01 22:24:41 +02002803 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002804 if (err < 0)
2805 goto done;
2806
Johan Hedberg03811012010-12-08 00:21:06 +02002807 err = msglen;
2808
2809done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002810 if (hdev)
2811 hci_dev_put(hdev);
2812
Johan Hedberg03811012010-12-08 00:21:06 +02002813 kfree(buf);
2814 return err;
2815}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002816
Johan Hedbergb24752f2011-11-03 14:40:33 +02002817static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2818{
2819 u8 *status = data;
2820
2821 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2822 mgmt_pending_remove(cmd);
2823}
2824
Johan Hedberg744cf192011-11-08 20:40:14 +02002825int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002826{
Johan Hedberg744cf192011-11-08 20:40:14 +02002827 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002828}
2829
Johan Hedberg744cf192011-11-08 20:40:14 +02002830int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002831{
Johan Hedberg5f159032012-03-02 03:13:19 +02002832 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002833
Johan Hedberg744cf192011-11-08 20:40:14 +02002834 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002835
Johan Hedberg744cf192011-11-08 20:40:14 +02002836 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002837}
2838
Johan Hedberg73f22f62010-12-29 16:00:25 +02002839struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002840 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002841 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002842 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002843};
2844
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002845static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002846{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002847 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002848
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002849 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002850
2851 list_del(&cmd->list);
2852
2853 if (match->sk == NULL) {
2854 match->sk = cmd->sk;
2855 sock_hold(match->sk);
2856 }
2857
2858 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002859}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002860
Johan Hedberg744cf192011-11-08 20:40:14 +02002861int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002862{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002863 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002864 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002865
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002866 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2867 return 0;
2868
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002869 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002870
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002871 if (powered) {
2872 u8 scan = 0;
2873
2874 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2875 scan |= SCAN_PAGE;
2876 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2877 scan |= SCAN_INQUIRY;
2878
2879 if (scan)
2880 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002881
2882 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002883 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002884 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002885 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002886 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002887 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002888 }
2889
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002890 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002891
2892 if (match.sk)
2893 sock_put(match.sk);
2894
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002895 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002896}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002897
Johan Hedberg744cf192011-11-08 20:40:14 +02002898int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002899{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002900 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002901 bool changed = false;
2902 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002903
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002904 if (discoverable) {
2905 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2906 changed = true;
2907 } else {
2908 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2909 changed = true;
2910 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002911
Johan Hedberged9b5f22012-02-21 20:47:06 +02002912 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002913 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002914
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002915 if (changed)
2916 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002917
Johan Hedberg73f22f62010-12-29 16:00:25 +02002918 if (match.sk)
2919 sock_put(match.sk);
2920
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002921 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002922}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002923
Johan Hedberg744cf192011-11-08 20:40:14 +02002924int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002925{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002926 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002927 bool changed = false;
2928 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002929
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002930 if (connectable) {
2931 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2932 changed = true;
2933 } else {
2934 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2935 changed = true;
2936 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002937
Johan Hedberged9b5f22012-02-21 20:47:06 +02002938 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002939 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002940
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002941 if (changed)
2942 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002943
2944 if (match.sk)
2945 sock_put(match.sk);
2946
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002947 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002948}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002949
Johan Hedberg744cf192011-11-08 20:40:14 +02002950int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002951{
Johan Hedbergca69b792011-11-11 18:10:00 +02002952 u8 mgmt_err = mgmt_status(status);
2953
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002954 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002955 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002956 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002957
2958 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002959 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002960 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002961
2962 return 0;
2963}
2964
Cristian Chilipirea53168e52012-05-09 08:44:52 +03002965int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2966 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002967{
Johan Hedberg86742e12011-11-07 23:13:38 +02002968 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002969
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002970 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002971
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002972 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002973 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03002974 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002975 ev.key.type = key->type;
2976 memcpy(ev.key.val, key->val, 16);
2977 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002978
Johan Hedberg744cf192011-11-08 20:40:14 +02002979 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002980}
Johan Hedbergf7520542011-01-20 12:34:39 +02002981
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002982int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2983{
2984 struct mgmt_ev_new_long_term_key ev;
2985
2986 memset(&ev, 0, sizeof(ev));
2987
2988 ev.store_hint = persistent;
2989 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03002990 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002991 ev.key.authenticated = key->authenticated;
2992 ev.key.enc_size = key->enc_size;
2993 ev.key.ediv = key->ediv;
2994
2995 if (key->type == HCI_SMP_LTK)
2996 ev.key.master = 1;
2997
2998 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2999 memcpy(ev.key.val, key->val, sizeof(key->val));
3000
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003001 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3002 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003003}
3004
Johan Hedbergafc747a2012-01-15 18:11:07 +02003005int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003006 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3007 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003008{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003009 char buf[512];
3010 struct mgmt_ev_device_connected *ev = (void *) buf;
3011 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003012
Johan Hedbergb644ba32012-01-17 21:48:47 +02003013 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003014 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003015
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003016 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003017
Johan Hedbergb644ba32012-01-17 21:48:47 +02003018 if (name_len > 0)
3019 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003020 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003021
3022 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003023 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003024 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003025
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003026 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003027
3028 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003030}
3031
Johan Hedberg8962ee72011-01-20 12:40:27 +02003032static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3033{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003034 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003035 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003036 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003037
Johan Hedberg88c3df12012-02-09 14:27:38 +02003038 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3039 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003040
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003041 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003042 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003043
3044 *sk = cmd->sk;
3045 sock_hold(*sk);
3046
Johan Hedberga664b5b2011-02-19 12:06:02 -03003047 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003048}
3049
Johan Hedberg124f6e32012-02-09 13:50:12 +02003050static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003051{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003052 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003053 struct mgmt_cp_unpair_device *cp = cmd->param;
3054 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003055
3056 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003057 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3058 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003059
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003060 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3061
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003062 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003063
3064 mgmt_pending_remove(cmd);
3065}
3066
Johan Hedbergafc747a2012-01-15 18:11:07 +02003067int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003068 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003069{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003070 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003071 struct sock *sk = NULL;
3072 int err;
3073
Johan Hedberg744cf192011-11-08 20:40:14 +02003074 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003075
Johan Hedbergf7520542011-01-20 12:34:39 +02003076 bacpy(&ev.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003077 ev.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003078
Johan Hedbergafc747a2012-01-15 18:11:07 +02003079 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003080 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003081
3082 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003083 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003084
Johan Hedberg124f6e32012-02-09 13:50:12 +02003085 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003086 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003087
Johan Hedberg8962ee72011-01-20 12:40:27 +02003088 return err;
3089}
3090
Johan Hedberg88c3df12012-02-09 14:27:38 +02003091int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003092 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003093{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003094 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003095 struct pending_cmd *cmd;
3096 int err;
3097
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003098 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003099 if (!cmd)
3100 return -ENOENT;
3101
Johan Hedberg88c3df12012-02-09 14:27:38 +02003102 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003103 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003104
Johan Hedberg88c3df12012-02-09 14:27:38 +02003105 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003106 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003107
Johan Hedberga664b5b2011-02-19 12:06:02 -03003108 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003109
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003110 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3111 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003112 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003113}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003114
Johan Hedberg48264f02011-11-09 13:58:58 +02003115int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003116 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003117{
3118 struct mgmt_ev_connect_failed ev;
3119
Johan Hedberg4c659c32011-11-07 23:13:39 +02003120 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003121 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003122 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003123
Johan Hedberg744cf192011-11-08 20:40:14 +02003124 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003125}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003126
Johan Hedberg744cf192011-11-08 20:40:14 +02003127int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003128{
3129 struct mgmt_ev_pin_code_request ev;
3130
Johan Hedbergd8457692012-02-17 14:24:57 +02003131 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003132 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003133 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003134
Johan Hedberg744cf192011-11-08 20:40:14 +02003135 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003136 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003137}
3138
Johan Hedberg744cf192011-11-08 20:40:14 +02003139int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003140 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003141{
3142 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003143 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003144 int err;
3145
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003146 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003147 if (!cmd)
3148 return -ENOENT;
3149
Johan Hedbergd8457692012-02-17 14:24:57 +02003150 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003151 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003152
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003153 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003154 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003155
Johan Hedberga664b5b2011-02-19 12:06:02 -03003156 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003157
3158 return err;
3159}
3160
Johan Hedberg744cf192011-11-08 20:40:14 +02003161int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003162 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003163{
3164 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003165 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003166 int err;
3167
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003168 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003169 if (!cmd)
3170 return -ENOENT;
3171
Johan Hedbergd8457692012-02-17 14:24:57 +02003172 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003173 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003174
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003175 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003176 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003177
Johan Hedberga664b5b2011-02-19 12:06:02 -03003178 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003179
3180 return err;
3181}
Johan Hedberga5c29682011-02-19 12:05:57 -03003182
Johan Hedberg744cf192011-11-08 20:40:14 +02003183int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003184 u8 link_type, u8 addr_type, __le32 value,
3185 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003186{
3187 struct mgmt_ev_user_confirm_request ev;
3188
Johan Hedberg744cf192011-11-08 20:40:14 +02003189 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003190
Johan Hedberg272d90d2012-02-09 15:26:12 +02003191 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003192 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003193 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003194 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003195
Johan Hedberg744cf192011-11-08 20:40:14 +02003196 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003198}
3199
Johan Hedberg272d90d2012-02-09 15:26:12 +02003200int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3201 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003202{
3203 struct mgmt_ev_user_passkey_request ev;
3204
3205 BT_DBG("%s", hdev->name);
3206
Johan Hedberg272d90d2012-02-09 15:26:12 +02003207 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003208 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003209
3210 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003211 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003212}
3213
Brian Gix0df4c182011-11-16 13:53:13 -08003214static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003215 u8 link_type, u8 addr_type, u8 status,
3216 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003217{
3218 struct pending_cmd *cmd;
3219 struct mgmt_rp_user_confirm_reply rp;
3220 int err;
3221
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003222 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003223 if (!cmd)
3224 return -ENOENT;
3225
Johan Hedberg272d90d2012-02-09 15:26:12 +02003226 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003227 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003228 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003229 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003230
Johan Hedberga664b5b2011-02-19 12:06:02 -03003231 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003232
3233 return err;
3234}
3235
Johan Hedberg744cf192011-11-08 20:40:14 +02003236int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003237 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003238{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003239 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003240 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003241}
3242
Johan Hedberg272d90d2012-02-09 15:26:12 +02003243int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003244 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003245{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003246 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003247 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003248}
Johan Hedberg2a611692011-02-19 12:06:00 -03003249
Brian Gix604086b2011-11-23 08:28:33 -08003250int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003251 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003252{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003253 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003254 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003255}
3256
Johan Hedberg272d90d2012-02-09 15:26:12 +02003257int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003258 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003259{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003260 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003261 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003262}
3263
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003264int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003265 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003266{
3267 struct mgmt_ev_auth_failed ev;
3268
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003269 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003270 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003271 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003272
Johan Hedberg744cf192011-11-08 20:40:14 +02003273 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003274}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003275
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003276int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3277{
3278 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003279 bool changed = false;
3280 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003281
3282 if (status) {
3283 u8 mgmt_err = mgmt_status(status);
3284 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003285 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003286 return 0;
3287 }
3288
Johan Hedberg47990ea2012-02-22 11:58:37 +02003289 if (test_bit(HCI_AUTH, &hdev->flags)) {
3290 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3291 changed = true;
3292 } else {
3293 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3294 changed = true;
3295 }
3296
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003297 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003298 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003299
Johan Hedberg47990ea2012-02-22 11:58:37 +02003300 if (changed)
3301 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003302
3303 if (match.sk)
3304 sock_put(match.sk);
3305
3306 return err;
3307}
3308
Johan Hedbergcacaf522012-02-21 00:52:42 +02003309static int clear_eir(struct hci_dev *hdev)
3310{
3311 struct hci_cp_write_eir cp;
3312
3313 if (!(hdev->features[6] & LMP_EXT_INQ))
3314 return 0;
3315
Johan Hedbergc80da272012-02-22 15:38:48 +02003316 memset(hdev->eir, 0, sizeof(hdev->eir));
3317
Johan Hedbergcacaf522012-02-21 00:52:42 +02003318 memset(&cp, 0, sizeof(cp));
3319
3320 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3321}
3322
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003323int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003324{
3325 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003326 bool changed = false;
3327 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003328
3329 if (status) {
3330 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003331
3332 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003333 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003334 err = new_settings(hdev, NULL);
3335
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003336 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3337 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003338
3339 return err;
3340 }
3341
3342 if (enable) {
3343 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3344 changed = true;
3345 } else {
3346 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3347 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003348 }
3349
3350 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3351
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003352 if (changed)
3353 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003354
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003355 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003356 sock_put(match.sk);
3357
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003358 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3359 update_eir(hdev);
3360 else
3361 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003362
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003363 return err;
3364}
3365
Johan Hedberg90e70452012-02-23 23:09:40 +02003366static void class_rsp(struct pending_cmd *cmd, void *data)
3367{
3368 struct cmd_lookup *match = data;
3369
3370 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003371 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003372
3373 list_del(&cmd->list);
3374
3375 if (match->sk == NULL) {
3376 match->sk = cmd->sk;
3377 sock_hold(match->sk);
3378 }
3379
3380 mgmt_pending_free(cmd);
3381}
3382
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003383int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003384 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003385{
Johan Hedberg90e70452012-02-23 23:09:40 +02003386 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3387 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003388
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003389 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3390
Johan Hedberg90e70452012-02-23 23:09:40 +02003391 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3392 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3393 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3394
3395 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003396 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3397 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003398
3399 if (match.sk)
3400 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003401
3402 return err;
3403}
3404
Johan Hedberg744cf192011-11-08 20:40:14 +02003405int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003406{
3407 struct pending_cmd *cmd;
3408 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003409 bool changed = false;
3410 int err = 0;
3411
3412 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3413 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3414 changed = true;
3415 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003416
3417 memset(&ev, 0, sizeof(ev));
3418 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003419 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003420
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003421 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003422 if (!cmd)
3423 goto send_event;
3424
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003425 /* Always assume that either the short or the complete name has
3426 * changed if there was a pending mgmt command */
3427 changed = true;
3428
Johan Hedbergb312b1612011-03-16 14:29:37 +02003429 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003430 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003431 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003432 goto failed;
3433 }
3434
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003435 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003436 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003437 if (err < 0)
3438 goto failed;
3439
3440send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003441 if (changed)
3442 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003443 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003444
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003445 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003446
3447failed:
3448 if (cmd)
3449 mgmt_pending_remove(cmd);
3450 return err;
3451}
Szymon Jancc35938b2011-03-22 13:12:21 +01003452
Johan Hedberg744cf192011-11-08 20:40:14 +02003453int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003454 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003455{
3456 struct pending_cmd *cmd;
3457 int err;
3458
Johan Hedberg744cf192011-11-08 20:40:14 +02003459 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003460
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003461 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003462 if (!cmd)
3463 return -ENOENT;
3464
3465 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003466 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3467 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003468 } else {
3469 struct mgmt_rp_read_local_oob_data rp;
3470
3471 memcpy(rp.hash, hash, sizeof(rp.hash));
3472 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3473
Johan Hedberg744cf192011-11-08 20:40:14 +02003474 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003475 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3476 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003477 }
3478
3479 mgmt_pending_remove(cmd);
3480
3481 return err;
3482}
Johan Hedberge17acd42011-03-30 23:57:16 +03003483
Johan Hedberg06199cf2012-02-22 16:37:11 +02003484int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3485{
3486 struct cmd_lookup match = { NULL, hdev };
3487 bool changed = false;
3488 int err = 0;
3489
3490 if (status) {
3491 u8 mgmt_err = mgmt_status(status);
3492
3493 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003494 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003495 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003496
Szymon Jancd97dcb62012-03-16 16:02:56 +01003497 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3498 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003499
3500 return err;
3501 }
3502
3503 if (enable) {
3504 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3505 changed = true;
3506 } else {
3507 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3508 changed = true;
3509 }
3510
3511 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3512
3513 if (changed)
3514 err = new_settings(hdev, match.sk);
3515
3516 if (match.sk)
3517 sock_put(match.sk);
3518
3519 return err;
3520}
3521
Johan Hedberg48264f02011-11-09 13:58:58 +02003522int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003523 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3524 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003525{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003526 char buf[512];
3527 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003528 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003529
Johan Hedberg1dc06092012-01-15 21:01:23 +02003530 /* Leave 5 bytes for a potential CoD field */
3531 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003532 return -EINVAL;
3533
Johan Hedberg1dc06092012-01-15 21:01:23 +02003534 memset(buf, 0, sizeof(buf));
3535
Johan Hedberge319d2e2012-01-15 19:51:59 +02003536 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003537 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003538 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003539 if (cfm_name)
3540 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003541 if (!ssp)
3542 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003543
Johan Hedberg1dc06092012-01-15 21:01:23 +02003544 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003545 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003546
Johan Hedberg1dc06092012-01-15 21:01:23 +02003547 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3548 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003549 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003550
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003551 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003552
3553 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003554
Johan Hedberge319d2e2012-01-15 19:51:59 +02003555 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003556}
Johan Hedberga88a9652011-03-30 13:18:12 +03003557
Johan Hedbergb644ba32012-01-17 21:48:47 +02003558int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003559 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003560{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003561 struct mgmt_ev_device_found *ev;
3562 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3563 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003564
Johan Hedbergb644ba32012-01-17 21:48:47 +02003565 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003566
Johan Hedbergb644ba32012-01-17 21:48:47 +02003567 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003568
Johan Hedbergb644ba32012-01-17 21:48:47 +02003569 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003570 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003571 ev->rssi = rssi;
3572
3573 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003574 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003575
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003576 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003577
Johan Hedberg053c7e02012-02-04 00:06:00 +02003578 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003579 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003580}
Johan Hedberg314b2382011-04-27 10:29:57 -04003581
Andre Guedes7a135102011-11-09 17:14:25 -03003582int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003583{
3584 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003585 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003586 int err;
3587
Andre Guedes203159d2012-02-13 15:41:01 -03003588 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3589
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003590 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003591 if (!cmd)
3592 return -ENOENT;
3593
Johan Hedbergf808e162012-02-19 12:52:07 +02003594 type = hdev->discovery.type;
3595
3596 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003597 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003598 mgmt_pending_remove(cmd);
3599
3600 return err;
3601}
3602
Andre Guedese6d465c2011-11-09 17:14:26 -03003603int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3604{
3605 struct pending_cmd *cmd;
3606 int err;
3607
3608 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3609 if (!cmd)
3610 return -ENOENT;
3611
Johan Hedbergd9306502012-02-20 23:25:18 +02003612 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003613 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003614 mgmt_pending_remove(cmd);
3615
3616 return err;
3617}
Johan Hedberg314b2382011-04-27 10:29:57 -04003618
Johan Hedberg744cf192011-11-08 20:40:14 +02003619int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003620{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003621 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003622 struct pending_cmd *cmd;
3623
Andre Guedes343fb142011-11-22 17:14:19 -03003624 BT_DBG("%s discovering %u", hdev->name, discovering);
3625
Johan Hedberg164a6e72011-11-01 17:06:44 +02003626 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003627 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003628 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003629 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003630
3631 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003632 u8 type = hdev->discovery.type;
3633
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003634 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3635 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003636 mgmt_pending_remove(cmd);
3637 }
3638
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003639 memset(&ev, 0, sizeof(ev));
3640 ev.type = hdev->discovery.type;
3641 ev.discovering = discovering;
3642
3643 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003644}
Antti Julku5e762442011-08-25 16:48:02 +03003645
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003646int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003647{
3648 struct pending_cmd *cmd;
3649 struct mgmt_ev_device_blocked ev;
3650
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003651 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003652
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003653 bacpy(&ev.addr.bdaddr, bdaddr);
3654 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003655
Johan Hedberg744cf192011-11-08 20:40:14 +02003656 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003657 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003658}
3659
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003660int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003661{
3662 struct pending_cmd *cmd;
3663 struct mgmt_ev_device_unblocked ev;
3664
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003665 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003666
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003667 bacpy(&ev.addr.bdaddr, bdaddr);
3668 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003669
Johan Hedberg744cf192011-11-08 20:40:14 +02003670 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003671 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003672}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003673
3674module_param(enable_hs, bool, 0644);
3675MODULE_PARM_DESC(enable_hs, "Enable High Speed support");