blob: 39395c7144aa16d0402ae9a71ecd2cd248a1affa [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
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060038#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Andre Guedes3fd24152012-02-03 17:48:01 -0300105/*
106 * These LE scan and inquiry parameters were chosen according to LE General
107 * Discovery Procedure specification.
108 */
109#define LE_SCAN_TYPE 0x01
110#define LE_SCAN_WIN 0x12
111#define LE_SCAN_INT 0x12
112#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300113#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300114
Andre Guedese8777522012-02-03 17:48:02 -0300115#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300116#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300117
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800118#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200119
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200120#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
121 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
122
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200123struct pending_cmd {
124 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200125 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200126 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100127 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200128 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300129 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200130};
131
Johan Hedbergca69b792011-11-11 18:10:00 +0200132/* HCI to MGMT error code conversion table */
133static u8 mgmt_status_table[] = {
134 MGMT_STATUS_SUCCESS,
135 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
136 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
137 MGMT_STATUS_FAILED, /* Hardware Failure */
138 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
139 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
140 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
141 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
142 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
143 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
145 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
146 MGMT_STATUS_BUSY, /* Command Disallowed */
147 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
148 MGMT_STATUS_REJECTED, /* Rejected Security */
149 MGMT_STATUS_REJECTED, /* Rejected Personal */
150 MGMT_STATUS_TIMEOUT, /* Host Timeout */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
153 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
154 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
155 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
156 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
157 MGMT_STATUS_BUSY, /* Repeated Attempts */
158 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
159 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
160 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
161 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
162 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
163 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
164 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
165 MGMT_STATUS_FAILED, /* Unspecified Error */
166 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
167 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
168 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
169 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
170 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
171 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
172 MGMT_STATUS_FAILED, /* Unit Link Key Used */
173 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
174 MGMT_STATUS_TIMEOUT, /* Instant Passed */
175 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
176 MGMT_STATUS_FAILED, /* Transaction Collision */
177 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
178 MGMT_STATUS_REJECTED, /* QoS Rejected */
179 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
180 MGMT_STATUS_REJECTED, /* Insufficient Security */
181 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
182 MGMT_STATUS_BUSY, /* Role Switch Pending */
183 MGMT_STATUS_FAILED, /* Slot Violation */
184 MGMT_STATUS_FAILED, /* Role Switch Failed */
185 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
186 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
187 MGMT_STATUS_BUSY, /* Host Busy Pairing */
188 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
189 MGMT_STATUS_BUSY, /* Controller Busy */
190 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
191 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
192 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
193 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
194 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
195};
196
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300197bool mgmt_valid_hdev(struct hci_dev *hdev)
198{
199 return hdev->dev_type == HCI_BREDR;
200}
201
Johan Hedbergca69b792011-11-11 18:10:00 +0200202static u8 mgmt_status(u8 hci_status)
203{
204 if (hci_status < ARRAY_SIZE(mgmt_status_table))
205 return mgmt_status_table[hci_status];
206
207 return MGMT_STATUS_FAILED;
208}
209
Szymon Janc4e51eae2011-02-25 19:05:48 +0100210static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200211{
212 struct sk_buff *skb;
213 struct mgmt_hdr *hdr;
214 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300215 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200216
Szymon Janc34eb5252011-02-28 14:10:08 +0100217 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200218
Andre Guedes790eff42012-06-07 19:05:46 -0300219 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 if (!skb)
221 return -ENOMEM;
222
223 hdr = (void *) skb_put(skb, sizeof(*hdr));
224
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530225 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100226 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200227 hdr->len = cpu_to_le16(sizeof(*ev));
228
229 ev = (void *) skb_put(skb, sizeof(*ev));
230 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200231 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 err = sock_queue_rcv_skb(sk, skb);
234 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200235 kfree_skb(skb);
236
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300237 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200238}
239
Johan Hedbergaee9b212012-02-18 15:07:59 +0200240static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300241 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200242{
243 struct sk_buff *skb;
244 struct mgmt_hdr *hdr;
245 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300246 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
248 BT_DBG("sock %p", sk);
249
Andre Guedes790eff42012-06-07 19:05:46 -0300250 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251 if (!skb)
252 return -ENOMEM;
253
254 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200255
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530256 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100257 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200258 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200259
Johan Hedberga38528f2011-01-22 06:46:43 +0200260 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200261 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200262 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100263
264 if (rp)
265 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200266
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 err = sock_queue_rcv_skb(sk, skb);
268 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200269 kfree_skb(skb);
270
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100271 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200272}
273
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
275 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200276{
277 struct mgmt_rp_read_version rp;
278
279 BT_DBG("sock %p", sk);
280
281 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200282 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200283
Johan Hedbergaee9b212012-02-18 15:07:59 +0200284 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200286}
287
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300288static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
289 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200290{
291 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200292 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
293 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200294 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295 size_t rp_size;
296 int i, err;
297
298 BT_DBG("sock %p", sk);
299
300 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
301
302 rp = kmalloc(rp_size, GFP_KERNEL);
303 if (!rp)
304 return -ENOMEM;
305
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200306 rp->num_commands = __constant_cpu_to_le16(num_commands);
307 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200308
309 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
310 put_unaligned_le16(mgmt_commands[i], opcode);
311
312 for (i = 0; i < num_events; i++, opcode++)
313 put_unaligned_le16(mgmt_events[i], opcode);
314
Johan Hedbergaee9b212012-02-18 15:07:59 +0200315 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300316 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200317 kfree(rp);
318
319 return err;
320}
321
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300322static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
323 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200326 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300329 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330
331 BT_DBG("sock %p", sk);
332
333 read_lock(&hci_dev_list_lock);
334
335 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300336 list_for_each_entry(d, &hci_dev_list, list) {
337 if (!mgmt_valid_hdev(d))
338 continue;
339
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340 count++;
341 }
342
Johan Hedberga38528f2011-01-22 06:46:43 +0200343 rp_len = sizeof(*rp) + (2 * count);
344 rp = kmalloc(rp_len, GFP_ATOMIC);
345 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100346 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200347 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100348 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349
Johan Hedberg476e44c2012-10-19 20:10:46 +0300350 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200351 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200352 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200353 continue;
354
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300355 if (!mgmt_valid_hdev(d))
356 continue;
357
Johan Hedberg476e44c2012-10-19 20:10:46 +0300358 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359 BT_DBG("Added hci%u", d->id);
360 }
361
Johan Hedberg476e44c2012-10-19 20:10:46 +0300362 rp->num_controllers = cpu_to_le16(count);
363 rp_len = sizeof(*rp) + (2 * count);
364
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200365 read_unlock(&hci_dev_list_lock);
366
Johan Hedbergaee9b212012-02-18 15:07:59 +0200367 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300368 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200369
Johan Hedberga38528f2011-01-22 06:46:43 +0200370 kfree(rp);
371
372 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200373}
374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200376{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200377 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200378
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200381
Andre Guedes9a1a1992012-07-24 15:03:48 -0300382 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200383 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200384
Andre Guedesed3fa312012-07-24 15:03:46 -0300385 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300386 settings |= MGMT_SETTING_CONNECTABLE;
387 settings |= MGMT_SETTING_FAST_CONNECTABLE;
388 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389 settings |= MGMT_SETTING_BREDR;
390 settings |= MGMT_SETTING_LINK_SECURITY;
391 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200392
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100393 if (enable_hs)
394 settings |= MGMT_SETTING_HS;
395
Andre Guedesc383ddc2012-07-24 15:03:47 -0300396 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200397 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200398
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 return settings;
400}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200401
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402static u32 get_current_settings(struct hci_dev *hdev)
403{
404 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200405
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200406 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100407 settings |= MGMT_SETTING_POWERED;
408
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200409 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_CONNECTABLE;
411
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200412 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_DISCOVERABLE;
414
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200415 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_PAIRABLE;
417
Andre Guedesed3fa312012-07-24 15:03:46 -0300418 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_BREDR;
420
Johan Hedberg06199cf2012-02-22 16:37:11 +0200421 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg47990ea2012-02-22 11:58:37 +0200424 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200426
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200427 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200428 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200429
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200430 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
431 settings |= MGMT_SETTING_HS;
432
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200433 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200434}
435
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300436#define PNP_INFO_SVCLASS_ID 0x1200
437
Johan Hedberg213202e2013-01-27 00:31:33 +0200438static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
439{
440 u8 *ptr = data, *uuids_start = NULL;
441 struct bt_uuid *uuid;
442
443 if (len < 4)
444 return ptr;
445
446 list_for_each_entry(uuid, &hdev->uuids, list) {
447 u16 uuid16;
448
449 if (uuid->size != 16)
450 continue;
451
452 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
453 if (uuid16 < 0x1100)
454 continue;
455
456 if (uuid16 == PNP_INFO_SVCLASS_ID)
457 continue;
458
459 if (!uuids_start) {
460 uuids_start = ptr;
461 uuids_start[0] = 1;
462 uuids_start[1] = EIR_UUID16_ALL;
463 ptr += 2;
464 }
465
466 /* Stop if not enough space to put next UUID */
467 if ((ptr - data) + sizeof(u16) > len) {
468 uuids_start[1] = EIR_UUID16_SOME;
469 break;
470 }
471
472 *ptr++ = (uuid16 & 0x00ff);
473 *ptr++ = (uuid16 & 0xff00) >> 8;
474 uuids_start[0] += sizeof(uuid16);
475 }
476
477 return ptr;
478}
479
Johan Hedbergcdf19632013-01-27 00:31:34 +0200480static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
481{
482 u8 *ptr = data, *uuids_start = NULL;
483 struct bt_uuid *uuid;
484
485 if (len < 6)
486 return ptr;
487
488 list_for_each_entry(uuid, &hdev->uuids, list) {
489 if (uuid->size != 32)
490 continue;
491
492 if (!uuids_start) {
493 uuids_start = ptr;
494 uuids_start[0] = 1;
495 uuids_start[1] = EIR_UUID32_ALL;
496 ptr += 2;
497 }
498
499 /* Stop if not enough space to put next UUID */
500 if ((ptr - data) + sizeof(u32) > len) {
501 uuids_start[1] = EIR_UUID32_SOME;
502 break;
503 }
504
505 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
506 ptr += sizeof(u32);
507 uuids_start[0] += sizeof(u32);
508 }
509
510 return ptr;
511}
512
Johan Hedbergc00d5752013-01-27 00:31:35 +0200513static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
514{
515 u8 *ptr = data, *uuids_start = NULL;
516 struct bt_uuid *uuid;
517
518 if (len < 18)
519 return ptr;
520
521 list_for_each_entry(uuid, &hdev->uuids, list) {
522 if (uuid->size != 128)
523 continue;
524
525 if (!uuids_start) {
526 uuids_start = ptr;
527 uuids_start[0] = 1;
528 uuids_start[1] = EIR_UUID128_ALL;
529 ptr += 2;
530 }
531
532 /* Stop if not enough space to put next UUID */
533 if ((ptr - data) + 16 > len) {
534 uuids_start[1] = EIR_UUID128_SOME;
535 break;
536 }
537
538 memcpy(ptr, uuid->uuid, 16);
539 ptr += 16;
540 uuids_start[0] += 16;
541 }
542
543 return ptr;
544}
545
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300546static void create_eir(struct hci_dev *hdev, u8 *data)
547{
548 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300549 size_t name_len;
550
551 name_len = strlen(hdev->dev_name);
552
553 if (name_len > 0) {
554 /* EIR Data type */
555 if (name_len > 48) {
556 name_len = 48;
557 ptr[1] = EIR_NAME_SHORT;
558 } else
559 ptr[1] = EIR_NAME_COMPLETE;
560
561 /* EIR Data length */
562 ptr[0] = name_len + 1;
563
564 memcpy(ptr + 2, hdev->dev_name, name_len);
565
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300566 ptr += (name_len + 2);
567 }
568
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100569 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700570 ptr[0] = 2;
571 ptr[1] = EIR_TX_POWER;
572 ptr[2] = (u8) hdev->inq_tx_power;
573
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700574 ptr += 3;
575 }
576
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700577 if (hdev->devid_source > 0) {
578 ptr[0] = 9;
579 ptr[1] = EIR_DEVICE_ID;
580
581 put_unaligned_le16(hdev->devid_source, ptr + 2);
582 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
583 put_unaligned_le16(hdev->devid_product, ptr + 6);
584 put_unaligned_le16(hdev->devid_version, ptr + 8);
585
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700586 ptr += 10;
587 }
588
Johan Hedberg213202e2013-01-27 00:31:33 +0200589 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200590 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200591 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300592}
593
594static int update_eir(struct hci_dev *hdev)
595{
596 struct hci_cp_write_eir cp;
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 Hedberg976eb202012-10-24 21:12:01 +0300601 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300602 return 0;
603
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200604 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300605 return 0;
606
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200607 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608 return 0;
609
610 memset(&cp, 0, sizeof(cp));
611
612 create_eir(hdev, cp.data);
613
614 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
615 return 0;
616
617 memcpy(hdev->eir, cp.data, sizeof(cp.data));
618
619 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
620}
621
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200622static u8 get_service_classes(struct hci_dev *hdev)
623{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300624 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200625 u8 val = 0;
626
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300627 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200629
630 return val;
631}
632
633static int update_class(struct hci_dev *hdev)
634{
635 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200636 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200637
638 BT_DBG("%s", hdev->name);
639
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200640 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200641 return 0;
642
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200643 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200644 return 0;
645
646 cod[0] = hdev->minor_class;
647 cod[1] = hdev->major_class;
648 cod[2] = get_service_classes(hdev);
649
650 if (memcmp(cod, hdev->dev_class, 3) == 0)
651 return 0;
652
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200653 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
654 if (err == 0)
655 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
656
657 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200658}
659
Johan Hedberg7d785252011-12-15 00:47:39 +0200660static void service_cache_off(struct work_struct *work)
661{
662 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300663 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200664
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200665 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200666 return;
667
668 hci_dev_lock(hdev);
669
670 update_eir(hdev);
671 update_class(hdev);
672
673 hci_dev_unlock(hdev);
674}
675
Johan Hedberg6a919082012-02-28 06:17:26 +0200676static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200677{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200678 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200679 return;
680
Johan Hedberg4f87da82012-03-02 19:55:56 +0200681 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200682
Johan Hedberg4f87da82012-03-02 19:55:56 +0200683 /* Non-mgmt controlled devices get this bit set
684 * implicitly so that pairing works for them, however
685 * for mgmt we require user-space to explicitly enable
686 * it
687 */
688 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200689}
690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200691static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200693{
694 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200696 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200697
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300698 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200699
Johan Hedberg03811012010-12-08 00:21:06 +0200700 memset(&rp, 0, sizeof(rp));
701
Johan Hedberg03811012010-12-08 00:21:06 +0200702 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200703
704 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200705 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200706
707 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
708 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
709
710 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200711
712 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200713 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300715 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200716
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200717 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300718 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200719}
720
721static void mgmt_pending_free(struct pending_cmd *cmd)
722{
723 sock_put(cmd->sk);
724 kfree(cmd->param);
725 kfree(cmd);
726}
727
728static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300729 struct hci_dev *hdev, void *data,
730 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200731{
732 struct pending_cmd *cmd;
733
Andre Guedes12b94562012-06-07 19:05:45 -0300734 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200735 if (!cmd)
736 return NULL;
737
738 cmd->opcode = opcode;
739 cmd->index = hdev->id;
740
Andre Guedes12b94562012-06-07 19:05:45 -0300741 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 if (!cmd->param) {
743 kfree(cmd);
744 return NULL;
745 }
746
747 if (data)
748 memcpy(cmd->param, data, len);
749
750 cmd->sk = sk;
751 sock_hold(sk);
752
753 list_add(&cmd->list, &hdev->mgmt_pending);
754
755 return cmd;
756}
757
758static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300759 void (*cb)(struct pending_cmd *cmd,
760 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300761 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200762{
Andre Guedesa3d09352013-02-01 11:21:30 -0300763 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Andre Guedesa3d09352013-02-01 11:21:30 -0300765 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200766 if (opcode > 0 && cmd->opcode != opcode)
767 continue;
768
769 cb(cmd, data);
770 }
771}
772
773static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
774{
775 struct pending_cmd *cmd;
776
777 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
778 if (cmd->opcode == opcode)
779 return cmd;
780 }
781
782 return NULL;
783}
784
785static void mgmt_pending_remove(struct pending_cmd *cmd)
786{
787 list_del(&cmd->list);
788 mgmt_pending_free(cmd);
789}
790
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200792{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200793 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200794
Johan Hedbergaee9b212012-02-18 15:07:59 +0200795 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200797}
798
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200799static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300800 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200801{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300802 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200803 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200804 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200806 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedberga7e80f22013-01-09 16:05:19 +0200808 if (cp->val != 0x00 && cp->val != 0x01)
809 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
810 MGMT_STATUS_INVALID_PARAMS);
811
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300812 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200813
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100814 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
815 cancel_delayed_work(&hdev->power_off);
816
817 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200818 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
819 data, len);
820 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100821 goto failed;
822 }
823 }
824
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200825 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200826 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200827 goto failed;
828 }
829
830 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200831 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300832 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200833 goto failed;
834 }
835
836 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
837 if (!cmd) {
838 err = -ENOMEM;
839 goto failed;
840 }
841
842 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200843 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200844 else
Johan Hedberg19202572013-01-14 22:33:51 +0200845 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200846
847 err = 0;
848
849failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300850 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200851 return err;
852}
853
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300854static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
855 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200856{
857 struct sk_buff *skb;
858 struct mgmt_hdr *hdr;
859
Andre Guedes790eff42012-06-07 19:05:46 -0300860 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200861 if (!skb)
862 return -ENOMEM;
863
864 hdr = (void *) skb_put(skb, sizeof(*hdr));
865 hdr->opcode = cpu_to_le16(event);
866 if (hdev)
867 hdr->index = cpu_to_le16(hdev->id);
868 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530869 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200870 hdr->len = cpu_to_le16(data_len);
871
872 if (data)
873 memcpy(skb_put(skb, data_len), data, data_len);
874
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100875 /* Time stamp */
876 __net_timestamp(skb);
877
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200878 hci_send_to_control(skb, skip_sk);
879 kfree_skb(skb);
880
881 return 0;
882}
883
884static int new_settings(struct hci_dev *hdev, struct sock *skip)
885{
886 __le32 ev;
887
888 ev = cpu_to_le32(get_current_settings(hdev));
889
890 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
891}
892
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200893static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300894 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200895{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300896 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200897 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200898 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200899 u8 scan;
900 int err;
901
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200902 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200903
Johan Hedberg33c525c2012-10-24 21:11:58 +0300904 if (!lmp_bredr_capable(hdev))
905 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
906 MGMT_STATUS_NOT_SUPPORTED);
907
Johan Hedberga7e80f22013-01-09 16:05:19 +0200908 if (cp->val != 0x00 && cp->val != 0x01)
909 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
910 MGMT_STATUS_INVALID_PARAMS);
911
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700912 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100913 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200914 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300915 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200916
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300917 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200918
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200919 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200920 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300921 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200922 goto failed;
923 }
924
925 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300926 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200927 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300928 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200929 goto failed;
930 }
931
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200932 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200933 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300934 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200935 goto failed;
936 }
937
938 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200939 bool changed = false;
940
941 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
942 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
943 changed = true;
944 }
945
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200946 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200947 if (err < 0)
948 goto failed;
949
950 if (changed)
951 err = new_settings(hdev, sk);
952
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200953 goto failed;
954 }
955
956 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100957 if (hdev->discov_timeout > 0) {
958 cancel_delayed_work(&hdev->discov_off);
959 hdev->discov_timeout = 0;
960 }
961
962 if (cp->val && timeout > 0) {
963 hdev->discov_timeout = timeout;
964 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
965 msecs_to_jiffies(hdev->discov_timeout * 1000));
966 }
967
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200968 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200969 goto failed;
970 }
971
972 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
973 if (!cmd) {
974 err = -ENOMEM;
975 goto failed;
976 }
977
978 scan = SCAN_PAGE;
979
980 if (cp->val)
981 scan |= SCAN_INQUIRY;
982 else
983 cancel_delayed_work(&hdev->discov_off);
984
985 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
986 if (err < 0)
987 mgmt_pending_remove(cmd);
988
Johan Hedberg03811012010-12-08 00:21:06 +0200989 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200990 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200991
992failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300993 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200994 return err;
995}
996
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200997static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300998 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200999{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001000 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001001 struct pending_cmd *cmd;
1002 u8 scan;
1003 int err;
1004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001005 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001006
Johan Hedberg33c525c2012-10-24 21:11:58 +03001007 if (!lmp_bredr_capable(hdev))
1008 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1009 MGMT_STATUS_NOT_SUPPORTED);
1010
Johan Hedberga7e80f22013-01-09 16:05:19 +02001011 if (cp->val != 0x00 && cp->val != 0x01)
1012 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1013 MGMT_STATUS_INVALID_PARAMS);
1014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001015 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001017 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001018 bool changed = false;
1019
1020 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1021 changed = true;
1022
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001023 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001024 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001025 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001026 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1027 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1028 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001029
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001030 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001031 if (err < 0)
1032 goto failed;
1033
1034 if (changed)
1035 err = new_settings(hdev, sk);
1036
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037 goto failed;
1038 }
1039
1040 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001041 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001042 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001043 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001044 goto failed;
1045 }
1046
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001047 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001048 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001049 goto failed;
1050 }
1051
1052 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1053 if (!cmd) {
1054 err = -ENOMEM;
1055 goto failed;
1056 }
1057
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001058 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001059 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001060 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001061 scan = 0;
1062
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001063 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001064 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001065 cancel_delayed_work(&hdev->discov_off);
1066 }
1067
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001068 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1069 if (err < 0)
1070 mgmt_pending_remove(cmd);
1071
1072failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001073 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001074 return err;
1075}
1076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001077static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001078 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001079{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001080 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001081 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001083 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001084
Johan Hedberga7e80f22013-01-09 16:05:19 +02001085 if (cp->val != 0x00 && cp->val != 0x01)
1086 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1087 MGMT_STATUS_INVALID_PARAMS);
1088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001089 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001090
1091 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001092 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001093 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001094 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001095
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001096 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001097 if (err < 0)
1098 goto failed;
1099
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001100 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001101
1102failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001103 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001104 return err;
1105}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001106
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001107static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1108 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001109{
1110 struct mgmt_mode *cp = data;
1111 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001112 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001113 int err;
1114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001115 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001116
Johan Hedberg33c525c2012-10-24 21:11:58 +03001117 if (!lmp_bredr_capable(hdev))
1118 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1119 MGMT_STATUS_NOT_SUPPORTED);
1120
Johan Hedberga7e80f22013-01-09 16:05:19 +02001121 if (cp->val != 0x00 && cp->val != 0x01)
1122 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1123 MGMT_STATUS_INVALID_PARAMS);
1124
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001125 hci_dev_lock(hdev);
1126
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001127 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001128 bool changed = false;
1129
1130 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001131 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001132 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1133 changed = true;
1134 }
1135
1136 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1137 if (err < 0)
1138 goto failed;
1139
1140 if (changed)
1141 err = new_settings(hdev, sk);
1142
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001143 goto failed;
1144 }
1145
1146 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001149 goto failed;
1150 }
1151
1152 val = !!cp->val;
1153
1154 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1155 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1156 goto failed;
1157 }
1158
1159 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1160 if (!cmd) {
1161 err = -ENOMEM;
1162 goto failed;
1163 }
1164
1165 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1166 if (err < 0) {
1167 mgmt_pending_remove(cmd);
1168 goto failed;
1169 }
1170
1171failed:
1172 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001173 return err;
1174}
1175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001176static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001177{
1178 struct mgmt_mode *cp = data;
1179 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001180 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001181 int err;
1182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001183 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001184
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001185 if (!lmp_ssp_capable(hdev))
1186 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1187 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001188
Johan Hedberga7e80f22013-01-09 16:05:19 +02001189 if (cp->val != 0x00 && cp->val != 0x01)
1190 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1191 MGMT_STATUS_INVALID_PARAMS);
1192
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001193 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001194
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001195 val = !!cp->val;
1196
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001197 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001198 bool changed = false;
1199
1200 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1201 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1202 changed = true;
1203 }
1204
1205 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1206 if (err < 0)
1207 goto failed;
1208
1209 if (changed)
1210 err = new_settings(hdev, sk);
1211
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001212 goto failed;
1213 }
1214
1215 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001216 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1217 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001218 goto failed;
1219 }
1220
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001221 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1222 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1223 goto failed;
1224 }
1225
1226 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1227 if (!cmd) {
1228 err = -ENOMEM;
1229 goto failed;
1230 }
1231
1232 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1233 if (err < 0) {
1234 mgmt_pending_remove(cmd);
1235 goto failed;
1236 }
1237
1238failed:
1239 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001240 return err;
1241}
1242
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001243static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001244{
1245 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001247 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001248
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001249 if (!enable_hs)
1250 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001251 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001252
Johan Hedberga7e80f22013-01-09 16:05:19 +02001253 if (cp->val != 0x00 && cp->val != 0x01)
1254 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1255 MGMT_STATUS_INVALID_PARAMS);
1256
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001257 if (cp->val)
1258 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1259 else
1260 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001262 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001263}
1264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001265static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001266{
1267 struct mgmt_mode *cp = data;
1268 struct hci_cp_write_le_host_supported hci_cp;
1269 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001270 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001271 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001272
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001273 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001274
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001275 if (!lmp_le_capable(hdev))
1276 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1277 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001278
Johan Hedberga7e80f22013-01-09 16:05:19 +02001279 if (cp->val != 0x00 && cp->val != 0x01)
1280 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1281 MGMT_STATUS_INVALID_PARAMS);
1282
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001283 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001284
1285 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001286 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001287
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001288 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001289 bool changed = false;
1290
1291 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1292 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1293 changed = true;
1294 }
1295
1296 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1297 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001298 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001299
1300 if (changed)
1301 err = new_settings(hdev, sk);
1302
Johan Hedberg1de028c2012-02-29 19:55:35 -08001303 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001304 }
1305
1306 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001307 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001308 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001309 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001310 }
1311
1312 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1313 if (!cmd) {
1314 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001315 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001316 }
1317
1318 memset(&hci_cp, 0, sizeof(hci_cp));
1319
1320 if (val) {
1321 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001322 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001323 }
1324
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001325 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1326 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301327 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001328 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001329
Johan Hedberg1de028c2012-02-29 19:55:35 -08001330unlock:
1331 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001332 return err;
1333}
1334
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001335static const u8 bluetooth_base_uuid[] = {
1336 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1337 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1338};
1339
1340static u8 get_uuid_size(const u8 *uuid)
1341{
1342 u32 val;
1343
1344 if (memcmp(uuid, bluetooth_base_uuid, 12))
1345 return 128;
1346
1347 val = get_unaligned_le32(&uuid[12]);
1348 if (val > 0xffff)
1349 return 32;
1350
1351 return 16;
1352}
1353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001354static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001355{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001356 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001357 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001358 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001359 int err;
1360
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001361 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001363 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001364
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001365 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001366 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001367 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001368 goto failed;
1369 }
1370
Andre Guedes92c4c202012-06-07 19:05:44 -03001371 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001372 if (!uuid) {
1373 err = -ENOMEM;
1374 goto failed;
1375 }
1376
1377 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001378 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001379 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001380
Johan Hedbergde66aa62013-01-27 00:31:27 +02001381 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001382
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001383 err = update_class(hdev);
1384 if (err < 0)
1385 goto failed;
1386
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001387 err = update_eir(hdev);
1388 if (err < 0)
1389 goto failed;
1390
Johan Hedberg90e70452012-02-23 23:09:40 +02001391 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001393 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001394 goto failed;
1395 }
1396
1397 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301398 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001399 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001400
1401failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001402 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001403 return err;
1404}
1405
Johan Hedberg24b78d02012-02-23 23:24:30 +02001406static bool enable_service_cache(struct hci_dev *hdev)
1407{
1408 if (!hdev_is_powered(hdev))
1409 return false;
1410
1411 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001412 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1413 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001414 return true;
1415 }
1416
1417 return false;
1418}
1419
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001420static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001421 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001422{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001423 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001424 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001425 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001426 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 +02001427 int err, found;
1428
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001429 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001430
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001431 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001432
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001433 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001434 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001435 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001436 goto unlock;
1437 }
1438
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001439 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1440 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001441
Johan Hedberg24b78d02012-02-23 23:24:30 +02001442 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001443 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001444 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001445 goto unlock;
1446 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001447
Johan Hedberg9246a862012-02-23 21:33:16 +02001448 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001449 }
1450
1451 found = 0;
1452
Johan Hedberg056341c2013-01-27 00:31:30 +02001453 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001454 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1455 continue;
1456
1457 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001458 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001459 found++;
1460 }
1461
1462 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001463 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001464 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001465 goto unlock;
1466 }
1467
Johan Hedberg9246a862012-02-23 21:33:16 +02001468update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001469 err = update_class(hdev);
1470 if (err < 0)
1471 goto unlock;
1472
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001473 err = update_eir(hdev);
1474 if (err < 0)
1475 goto unlock;
1476
Johan Hedberg90e70452012-02-23 23:09:40 +02001477 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001478 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001479 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001480 goto unlock;
1481 }
1482
1483 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301484 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001485 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001486
1487unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001488 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001489 return err;
1490}
1491
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001492static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001493 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001494{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001495 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001496 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001497 int err;
1498
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001499 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001500
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001501 if (!lmp_bredr_capable(hdev))
1502 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1503 MGMT_STATUS_NOT_SUPPORTED);
1504
1505 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags))
1506 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1507 MGMT_STATUS_BUSY);
1508
1509 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0)
1510 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1511 MGMT_STATUS_INVALID_PARAMS);
1512
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001513 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001514
1515 hdev->major_class = cp->major;
1516 hdev->minor_class = cp->minor;
1517
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001518 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001519 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001520 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001521 goto unlock;
1522 }
1523
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001524 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001525 hci_dev_unlock(hdev);
1526 cancel_delayed_work_sync(&hdev->service_cache);
1527 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001528 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001529 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001530
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001531 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001532 if (err < 0)
1533 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001534
Johan Hedberg90e70452012-02-23 23:09:40 +02001535 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001536 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001537 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001538 goto unlock;
1539 }
1540
1541 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301542 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001543 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001544
Johan Hedbergb5235a62012-02-21 14:32:24 +02001545unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001546 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001547 return err;
1548}
1549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001550static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001551 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001552{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001553 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001554 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001555 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001556
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001557 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001558
Johan Hedberg86742e12011-11-07 23:13:38 +02001559 expected_len = sizeof(*cp) + key_count *
1560 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001561 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001562 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001563 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001564 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001565 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001566 }
1567
Johan Hedberg4ae14302013-01-20 14:27:13 +02001568 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1569 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1570 MGMT_STATUS_INVALID_PARAMS);
1571
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001572 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001573 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001574
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001575 for (i = 0; i < key_count; i++) {
1576 struct mgmt_link_key_info *key = &cp->keys[i];
1577
1578 if (key->addr.type != BDADDR_BREDR)
1579 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1580 MGMT_STATUS_INVALID_PARAMS);
1581 }
1582
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001583 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001584
1585 hci_link_keys_clear(hdev);
1586
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001587 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001588
1589 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001590 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001591 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001592 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001593
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001594 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001595 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001596
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001597 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001598 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001599 }
1600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001601 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001602
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001603 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001604
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001605 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001606}
1607
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001608static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001609 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001610{
1611 struct mgmt_ev_device_unpaired ev;
1612
1613 bacpy(&ev.addr.bdaddr, bdaddr);
1614 ev.addr.type = addr_type;
1615
1616 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001617 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001618}
1619
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001620static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001621 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001622{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001623 struct mgmt_cp_unpair_device *cp = data;
1624 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001625 struct hci_cp_disconnect dc;
1626 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001627 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001628 int err;
1629
Johan Hedberga8a1d192011-11-10 15:54:38 +02001630 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001631 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1632 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001633
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001634 if (!bdaddr_type_is_valid(cp->addr.type))
1635 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1636 MGMT_STATUS_INVALID_PARAMS,
1637 &rp, sizeof(rp));
1638
Johan Hedberg118da702013-01-20 14:27:20 +02001639 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1640 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1641 MGMT_STATUS_INVALID_PARAMS,
1642 &rp, sizeof(rp));
1643
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001644 hci_dev_lock(hdev);
1645
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001646 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001647 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001648 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001649 goto unlock;
1650 }
1651
Andre Guedes591f47f2012-04-24 21:02:49 -03001652 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001653 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1654 else
1655 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001656
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001657 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001658 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001659 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001660 goto unlock;
1661 }
1662
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001663 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001664 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001665 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001666 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001667 else
1668 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001669 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001670 } else {
1671 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001672 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001673
Johan Hedberga8a1d192011-11-10 15:54:38 +02001674 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001675 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001676 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001677 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001678 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001679 }
1680
Johan Hedberg124f6e32012-02-09 13:50:12 +02001681 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001682 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001683 if (!cmd) {
1684 err = -ENOMEM;
1685 goto unlock;
1686 }
1687
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001688 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001689 dc.reason = 0x13; /* Remote User Terminated Connection */
1690 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1691 if (err < 0)
1692 mgmt_pending_remove(cmd);
1693
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001694unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001695 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001696 return err;
1697}
1698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001699static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001700 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001701{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001702 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001703 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001704 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001705 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001706 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001707 int err;
1708
1709 BT_DBG("");
1710
Johan Hedberg06a63b12013-01-20 14:27:21 +02001711 memset(&rp, 0, sizeof(rp));
1712 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1713 rp.addr.type = cp->addr.type;
1714
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001715 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001716 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1717 MGMT_STATUS_INVALID_PARAMS,
1718 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001719
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001720 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001721
1722 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001723 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1724 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001725 goto failed;
1726 }
1727
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001728 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001729 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1730 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001731 goto failed;
1732 }
1733
Andre Guedes591f47f2012-04-24 21:02:49 -03001734 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001735 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1736 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001737 else
1738 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001739
Vishal Agarwalf9607272012-06-13 05:32:43 +05301740 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001741 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1742 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001743 goto failed;
1744 }
1745
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001746 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001747 if (!cmd) {
1748 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001749 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001750 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001751
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001752 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001753 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001754
1755 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1756 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001757 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001758
1759failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001760 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001761 return err;
1762}
1763
Andre Guedes57c14772012-04-24 21:02:50 -03001764static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001765{
1766 switch (link_type) {
1767 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001768 switch (addr_type) {
1769 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001770 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001771
Johan Hedberg48264f02011-11-09 13:58:58 +02001772 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001773 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001774 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001775 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001776
Johan Hedberg4c659c32011-11-07 23:13:39 +02001777 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001778 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001779 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001780 }
1781}
1782
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001783static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1784 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001785{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001786 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001787 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001788 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001789 int err;
1790 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001791
1792 BT_DBG("");
1793
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001794 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001795
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001796 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001797 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001798 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001799 goto unlock;
1800 }
1801
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001802 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001803 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1804 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001805 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001806 }
1807
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001808 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001809 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001810 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001811 err = -ENOMEM;
1812 goto unlock;
1813 }
1814
Johan Hedberg2784eb42011-01-21 13:56:35 +02001815 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001816 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001817 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1818 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001819 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001820 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001821 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001822 continue;
1823 i++;
1824 }
1825
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001826 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001827
Johan Hedberg4c659c32011-11-07 23:13:39 +02001828 /* Recalculate length in case of filtered SCO connections, etc */
1829 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001830
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001831 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001832 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001833
Johan Hedberga38528f2011-01-22 06:46:43 +02001834 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001835
1836unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001837 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001838 return err;
1839}
1840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001843{
1844 struct pending_cmd *cmd;
1845 int err;
1846
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001847 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001848 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001849 if (!cmd)
1850 return -ENOMEM;
1851
Johan Hedbergd8457692012-02-17 14:24:57 +02001852 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001853 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001854 if (err < 0)
1855 mgmt_pending_remove(cmd);
1856
1857 return err;
1858}
1859
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001860static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001861 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001862{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001863 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001864 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001865 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001866 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001867 int err;
1868
1869 BT_DBG("");
1870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001871 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001872
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001873 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001874 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001875 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001876 goto failed;
1877 }
1878
Johan Hedbergd8457692012-02-17 14:24:57 +02001879 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001880 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001881 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001882 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001883 goto failed;
1884 }
1885
1886 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001887 struct mgmt_cp_pin_code_neg_reply ncp;
1888
1889 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001890
1891 BT_ERR("PIN code is not 16 bytes long");
1892
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001893 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001894 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001895 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001896 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001897
1898 goto failed;
1899 }
1900
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001901 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001902 if (!cmd) {
1903 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001904 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001905 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001906
Johan Hedbergd8457692012-02-17 14:24:57 +02001907 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001908 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001909 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001910
1911 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1912 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001913 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001914
1915failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001916 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001917 return err;
1918}
1919
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001920static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1921 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001922{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001923 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001924
1925 BT_DBG("");
1926
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001927 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001928
1929 hdev->io_capability = cp->io_capability;
1930
1931 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001932 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001933
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001934 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001935
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001936 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1937 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001938}
1939
Gustavo Padovan6039aa72012-05-23 04:04:18 -03001940static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001941{
1942 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001943 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001944
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001945 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001946 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1947 continue;
1948
Johan Hedberge9a416b2011-02-19 12:05:56 -03001949 if (cmd->user_data != conn)
1950 continue;
1951
1952 return cmd;
1953 }
1954
1955 return NULL;
1956}
1957
1958static void pairing_complete(struct pending_cmd *cmd, u8 status)
1959{
1960 struct mgmt_rp_pair_device rp;
1961 struct hci_conn *conn = cmd->user_data;
1962
Johan Hedbergba4e5642011-11-11 00:07:34 +02001963 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001964 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001965
Johan Hedbergaee9b212012-02-18 15:07:59 +02001966 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001967 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001968
1969 /* So we don't get further callbacks for this connection */
1970 conn->connect_cfm_cb = NULL;
1971 conn->security_cfm_cb = NULL;
1972 conn->disconn_cfm_cb = NULL;
1973
1974 hci_conn_put(conn);
1975
Johan Hedberga664b5b2011-02-19 12:06:02 -03001976 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001977}
1978
1979static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1980{
1981 struct pending_cmd *cmd;
1982
1983 BT_DBG("status %u", status);
1984
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001985 cmd = find_pairing(conn);
1986 if (!cmd)
1987 BT_DBG("Unable to find a pending command");
1988 else
Johan Hedberge2113262012-02-18 15:20:03 +02001989 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001990}
1991
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301992static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1993{
1994 struct pending_cmd *cmd;
1995
1996 BT_DBG("status %u", status);
1997
1998 if (!status)
1999 return;
2000
2001 cmd = find_pairing(conn);
2002 if (!cmd)
2003 BT_DBG("Unable to find a pending command");
2004 else
2005 pairing_complete(cmd, mgmt_status(status));
2006}
2007
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002008static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002009 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002010{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002011 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002012 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002013 struct pending_cmd *cmd;
2014 u8 sec_level, auth_type;
2015 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002016 int err;
2017
2018 BT_DBG("");
2019
Szymon Jancf950a30e2013-01-18 12:48:07 +01002020 memset(&rp, 0, sizeof(rp));
2021 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2022 rp.addr.type = cp->addr.type;
2023
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002024 if (!bdaddr_type_is_valid(cp->addr.type))
2025 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2026 MGMT_STATUS_INVALID_PARAMS,
2027 &rp, sizeof(rp));
2028
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002029 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002030
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002031 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002032 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2033 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002034 goto unlock;
2035 }
2036
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002037 sec_level = BT_SECURITY_MEDIUM;
2038 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002039 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002040 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002041 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002042
Andre Guedes591f47f2012-04-24 21:02:49 -03002043 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002044 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2045 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002046 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002047 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2048 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002049
Ville Tervo30e76272011-02-22 16:10:53 -03002050 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002051 int status;
2052
2053 if (PTR_ERR(conn) == -EBUSY)
2054 status = MGMT_STATUS_BUSY;
2055 else
2056 status = MGMT_STATUS_CONNECT_FAILED;
2057
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002058 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002059 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002060 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002061 goto unlock;
2062 }
2063
2064 if (conn->connect_cfm_cb) {
2065 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002066 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002067 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002068 goto unlock;
2069 }
2070
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002071 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002072 if (!cmd) {
2073 err = -ENOMEM;
2074 hci_conn_put(conn);
2075 goto unlock;
2076 }
2077
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002078 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002079 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002080 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302081 else
2082 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002083
Johan Hedberge9a416b2011-02-19 12:05:56 -03002084 conn->security_cfm_cb = pairing_complete_cb;
2085 conn->disconn_cfm_cb = pairing_complete_cb;
2086 conn->io_capability = cp->io_cap;
2087 cmd->user_data = conn;
2088
2089 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002090 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002091 pairing_complete(cmd, 0);
2092
2093 err = 0;
2094
2095unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002096 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002097 return err;
2098}
2099
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002100static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2101 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002102{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002103 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002104 struct pending_cmd *cmd;
2105 struct hci_conn *conn;
2106 int err;
2107
2108 BT_DBG("");
2109
Johan Hedberg28424702012-02-02 04:02:29 +02002110 hci_dev_lock(hdev);
2111
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002112 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002113 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002114 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002115 goto unlock;
2116 }
2117
Johan Hedberg28424702012-02-02 04:02:29 +02002118 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2119 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002120 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002121 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002122 goto unlock;
2123 }
2124
2125 conn = cmd->user_data;
2126
2127 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002128 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002129 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002130 goto unlock;
2131 }
2132
2133 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002135 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002136 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002137unlock:
2138 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002139 return err;
2140}
2141
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002142static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002143 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2144 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002145{
Johan Hedberga5c29682011-02-19 12:05:57 -03002146 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002147 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002148 int err;
2149
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002150 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002151
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002152 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002153 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002154 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002155 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002156 }
2157
Andre Guedes591f47f2012-04-24 21:02:49 -03002158 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002159 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2160 else
Brian Gix47c15e22011-11-16 13:53:14 -08002161 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002162
Johan Hedberg272d90d2012-02-09 15:26:12 +02002163 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002164 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002165 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002166 goto done;
2167 }
2168
Andre Guedes591f47f2012-04-24 21:02:49 -03002169 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002170 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002171 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002172
Brian Gix5fe57d92011-12-21 16:12:13 -08002173 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002174 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002175 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002176 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002179
Brian Gix47c15e22011-11-16 13:53:14 -08002180 goto done;
2181 }
2182
Brian Gix0df4c182011-11-16 13:53:13 -08002183 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002184 if (!cmd) {
2185 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002186 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002187 }
2188
Brian Gix0df4c182011-11-16 13:53:13 -08002189 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002190 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2191 struct hci_cp_user_passkey_reply cp;
2192
2193 bacpy(&cp.bdaddr, bdaddr);
2194 cp.passkey = passkey;
2195 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2196 } else
2197 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2198
Johan Hedberga664b5b2011-02-19 12:06:02 -03002199 if (err < 0)
2200 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002201
Brian Gix0df4c182011-11-16 13:53:13 -08002202done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002203 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002204 return err;
2205}
2206
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302207static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2208 void *data, u16 len)
2209{
2210 struct mgmt_cp_pin_code_neg_reply *cp = data;
2211
2212 BT_DBG("");
2213
2214 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2215 MGMT_OP_PIN_CODE_NEG_REPLY,
2216 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2217}
2218
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002219static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2220 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002221{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002222 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002223
2224 BT_DBG("");
2225
2226 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002227 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002228 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002229
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002230 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 MGMT_OP_USER_CONFIRM_REPLY,
2232 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002233}
2234
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002235static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002236 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002237{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002238 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002239
2240 BT_DBG("");
2241
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002242 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002243 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2244 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002245}
2246
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002247static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2248 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002249{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002250 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002251
2252 BT_DBG("");
2253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002254 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002255 MGMT_OP_USER_PASSKEY_REPLY,
2256 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002257}
2258
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002259static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002260 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002261{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002262 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002263
2264 BT_DBG("");
2265
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002266 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002267 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2268 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002269}
2270
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002271static int update_name(struct hci_dev *hdev, const char *name)
2272{
2273 struct hci_cp_write_local_name cp;
2274
2275 memcpy(cp.name, name, sizeof(cp.name));
2276
2277 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2278}
2279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002280static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002281 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002282{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002283 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002284 struct pending_cmd *cmd;
2285 int err;
2286
2287 BT_DBG("");
2288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002289 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002290
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002291 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002292
Johan Hedbergb5235a62012-02-21 14:32:24 +02002293 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002294 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002295
2296 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002297 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002298 if (err < 0)
2299 goto failed;
2300
2301 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002302 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002303
Johan Hedbergb5235a62012-02-21 14:32:24 +02002304 goto failed;
2305 }
2306
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002307 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002308 if (!cmd) {
2309 err = -ENOMEM;
2310 goto failed;
2311 }
2312
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002313 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002314 if (err < 0)
2315 mgmt_pending_remove(cmd);
2316
2317failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002318 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002319 return err;
2320}
2321
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002322static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002324{
Szymon Jancc35938b2011-03-22 13:12:21 +01002325 struct pending_cmd *cmd;
2326 int err;
2327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002328 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002329
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002330 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002331
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002332 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002333 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002334 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002335 goto unlock;
2336 }
2337
Andre Guedes9a1a1992012-07-24 15:03:48 -03002338 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002339 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002341 goto unlock;
2342 }
2343
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002344 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002345 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002346 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002347 goto unlock;
2348 }
2349
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002350 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002351 if (!cmd) {
2352 err = -ENOMEM;
2353 goto unlock;
2354 }
2355
2356 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2357 if (err < 0)
2358 mgmt_pending_remove(cmd);
2359
2360unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002362 return err;
2363}
2364
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002365static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002366 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002367{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002368 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002369 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002370 int err;
2371
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002372 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002373
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002374 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002375
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002376 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002377 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002378 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002379 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002380 else
Szymon Janca6785be2012-12-13 15:11:21 +01002381 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002383 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002384 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002385
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002386 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002387 return err;
2388}
2389
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002390static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002391 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002392{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002393 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002394 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002395 int err;
2396
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002397 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002398
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002399 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002400
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002401 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002402 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002403 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002404 else
Szymon Janca6785be2012-12-13 15:11:21 +01002405 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002406
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002407 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002408 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002409
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002410 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002411 return err;
2412}
2413
Andre Guedes5e0452c2012-02-17 20:39:38 -03002414int mgmt_interleaved_discovery(struct hci_dev *hdev)
2415{
2416 int err;
2417
2418 BT_DBG("%s", hdev->name);
2419
2420 hci_dev_lock(hdev);
2421
2422 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2423 if (err < 0)
2424 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2425
2426 hci_dev_unlock(hdev);
2427
2428 return err;
2429}
2430
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002431static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002432 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002433{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002434 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002435 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002436 int err;
2437
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002438 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002439
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002440 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002441
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002442 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002443 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002444 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002445 goto failed;
2446 }
2447
Andre Guedes642be6c2012-03-21 00:03:37 -03002448 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2449 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2450 MGMT_STATUS_BUSY);
2451 goto failed;
2452 }
2453
Johan Hedbergff9ef572012-01-04 14:23:45 +02002454 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002455 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002456 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002457 goto failed;
2458 }
2459
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002460 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002461 if (!cmd) {
2462 err = -ENOMEM;
2463 goto failed;
2464 }
2465
Andre Guedes4aab14e2012-02-17 20:39:36 -03002466 hdev->discovery.type = cp->type;
2467
2468 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002469 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002470 if (!lmp_bredr_capable(hdev)) {
2471 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2472 MGMT_STATUS_NOT_SUPPORTED);
2473 mgmt_pending_remove(cmd);
2474 goto failed;
2475 }
2476
2477 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002478 break;
2479
2480 case DISCOV_TYPE_LE:
Johan Hedberg04106752013-01-10 14:54:09 +02002481 if (!lmp_host_le_capable(hdev)) {
2482 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2483 MGMT_STATUS_NOT_SUPPORTED);
2484 mgmt_pending_remove(cmd);
2485 goto failed;
2486 }
2487
2488 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2489 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002490 break;
2491
Andre Guedes5e0452c2012-02-17 20:39:38 -03002492 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg04106752013-01-10 14:54:09 +02002493 if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) {
2494 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2495 MGMT_STATUS_NOT_SUPPORTED);
2496 mgmt_pending_remove(cmd);
2497 goto failed;
2498 }
2499
2500 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN,
2501 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002502 break;
2503
Andre Guedesf39799f2012-02-17 20:39:35 -03002504 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002505 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2506 MGMT_STATUS_INVALID_PARAMS);
2507 mgmt_pending_remove(cmd);
2508 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002509 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002510
Johan Hedberg14a53662011-04-27 10:29:56 -04002511 if (err < 0)
2512 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002513 else
2514 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002515
2516failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002517 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002518 return err;
2519}
2520
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002521static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002522 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002523{
Johan Hedbergd9306502012-02-20 23:25:18 +02002524 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002525 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002526 struct hci_cp_remote_name_req_cancel cp;
2527 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002528 int err;
2529
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002530 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002531
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002532 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002533
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002534 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002535 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2537 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002538 goto unlock;
2539 }
2540
2541 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002542 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002543 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2544 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002545 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002546 }
2547
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002548 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002549 if (!cmd) {
2550 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002551 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002552 }
2553
Andre Guedese0d9727e2012-03-20 15:15:36 -03002554 switch (hdev->discovery.state) {
2555 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002556 if (test_bit(HCI_INQUIRY, &hdev->flags))
2557 err = hci_cancel_inquiry(hdev);
2558 else
2559 err = hci_cancel_le_scan(hdev);
2560
Andre Guedese0d9727e2012-03-20 15:15:36 -03002561 break;
2562
2563 case DISCOVERY_RESOLVING:
2564 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002565 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002566 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002567 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002568 err = cmd_complete(sk, hdev->id,
2569 MGMT_OP_STOP_DISCOVERY, 0,
2570 &mgmt_cp->type,
2571 sizeof(mgmt_cp->type));
2572 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2573 goto unlock;
2574 }
2575
2576 bacpy(&cp.bdaddr, &e->data.bdaddr);
2577 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2578 sizeof(cp), &cp);
2579
2580 break;
2581
2582 default:
2583 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2584 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002585 }
2586
Johan Hedberg14a53662011-04-27 10:29:56 -04002587 if (err < 0)
2588 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002589 else
2590 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002591
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002592unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002593 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002594 return err;
2595}
2596
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002597static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002598 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002599{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002600 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002601 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002602 int err;
2603
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002604 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002605
Johan Hedberg561aafb2012-01-04 13:31:59 +02002606 hci_dev_lock(hdev);
2607
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002608 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002609 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002610 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002611 goto failed;
2612 }
2613
Johan Hedberga198e7b2012-02-17 14:27:06 +02002614 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002615 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002616 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002617 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002618 goto failed;
2619 }
2620
2621 if (cp->name_known) {
2622 e->name_state = NAME_KNOWN;
2623 list_del(&e->list);
2624 } else {
2625 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002626 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002627 }
2628
Johan Hedberge3846622013-01-09 15:29:33 +02002629 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
2630 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02002631
2632failed:
2633 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002634 return err;
2635}
2636
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002639{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002640 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002641 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002642 int err;
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002645
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002646 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002647 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
2648 MGMT_STATUS_INVALID_PARAMS,
2649 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002650
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002651 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002652
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002653 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002654 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002655 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002656 else
Szymon Janca6785be2012-12-13 15:11:21 +01002657 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002658
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002659 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002660 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002661
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002662 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002663
2664 return err;
2665}
2666
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002667static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002668 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002669{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002670 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002671 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002672 int err;
2673
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002674 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002675
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002676 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002677 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
2678 MGMT_STATUS_INVALID_PARAMS,
2679 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002680
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002681 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002682
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002683 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002684 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002685 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002686 else
Szymon Janca6785be2012-12-13 15:11:21 +01002687 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002688
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002689 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002690 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002691
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002692 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002693
2694 return err;
2695}
2696
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002697static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2698 u16 len)
2699{
2700 struct mgmt_cp_set_device_id *cp = data;
2701 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002702 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002703
2704 BT_DBG("%s", hdev->name);
2705
Szymon Jancc72d4b82012-03-16 16:02:57 +01002706 source = __le16_to_cpu(cp->source);
2707
2708 if (source > 0x0002)
2709 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2710 MGMT_STATUS_INVALID_PARAMS);
2711
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002712 hci_dev_lock(hdev);
2713
Szymon Jancc72d4b82012-03-16 16:02:57 +01002714 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002715 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2716 hdev->devid_product = __le16_to_cpu(cp->product);
2717 hdev->devid_version = __le16_to_cpu(cp->version);
2718
2719 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2720
2721 update_eir(hdev);
2722
2723 hci_dev_unlock(hdev);
2724
2725 return err;
2726}
2727
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002728static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002729 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002730{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002731 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002732 struct hci_cp_write_page_scan_activity acp;
2733 u8 type;
2734 int err;
2735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002736 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002737
Johan Hedberg33c525c2012-10-24 21:11:58 +03002738 if (!lmp_bredr_capable(hdev))
2739 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2740 MGMT_STATUS_NOT_SUPPORTED);
2741
Johan Hedberga7e80f22013-01-09 16:05:19 +02002742 if (cp->val != 0x00 && cp->val != 0x01)
2743 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2744 MGMT_STATUS_INVALID_PARAMS);
2745
Johan Hedberg5400c042012-02-21 16:40:33 +02002746 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002747 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002748 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002749
2750 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002751 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002752 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002753
2754 hci_dev_lock(hdev);
2755
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002756 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002757 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002758
Johan Hedberg83ce9a062012-06-28 13:44:30 +03002759 /* 160 msec page scan interval */
2760 acp.interval = __constant_cpu_to_le16(0x0100);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002761 } else {
2762 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002763
2764 /* default 1.28 sec page scan */
2765 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002766 }
2767
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002768 /* default 11.25 msec page scan window */
2769 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002770
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002771 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2772 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002773 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002774 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002775 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002776 goto done;
2777 }
2778
2779 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2780 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002781 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002782 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002783 goto done;
2784 }
2785
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002786 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002787 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002788done:
2789 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002790 return err;
2791}
2792
Johan Hedberg3f706b72013-01-20 14:27:16 +02002793static bool ltk_is_valid(struct mgmt_ltk_info *key)
2794{
Johan Hedberg44b20d32013-01-20 14:27:17 +02002795 if (key->authenticated != 0x00 && key->authenticated != 0x01)
2796 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02002797 if (key->master != 0x00 && key->master != 0x01)
2798 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002799 if (!bdaddr_type_is_le(key->addr.type))
2800 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02002801 return true;
2802}
2803
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002804static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002805 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002806{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002807 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2808 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002809 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002810
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002811 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002812
2813 expected_len = sizeof(*cp) + key_count *
2814 sizeof(struct mgmt_ltk_info);
2815 if (expected_len != len) {
2816 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002817 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002818 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02002819 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002820 }
2821
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002822 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002823
Johan Hedberg54ad6d82013-01-20 14:27:15 +02002824 for (i = 0; i < key_count; i++) {
2825 struct mgmt_ltk_info *key = &cp->keys[i];
2826
Johan Hedberg3f706b72013-01-20 14:27:16 +02002827 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02002828 return cmd_status(sk, hdev->id,
2829 MGMT_OP_LOAD_LONG_TERM_KEYS,
2830 MGMT_STATUS_INVALID_PARAMS);
2831 }
2832
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002833 hci_dev_lock(hdev);
2834
2835 hci_smp_ltks_clear(hdev);
2836
2837 for (i = 0; i < key_count; i++) {
2838 struct mgmt_ltk_info *key = &cp->keys[i];
2839 u8 type;
2840
2841 if (key->master)
2842 type = HCI_SMP_LTK;
2843 else
2844 type = HCI_SMP_LTK_SLAVE;
2845
Hemant Gupta4596fde2012-04-16 14:57:40 +05302846 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002847 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002848 type, 0, key->authenticated, key->val,
2849 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002850 }
2851
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002852 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
2853 NULL, 0);
2854
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002855 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002856
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002857 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002858}
2859
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002860static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002861 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2862 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002863 bool var_len;
2864 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002865} mgmt_handlers[] = {
2866 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002867 { read_version, false, MGMT_READ_VERSION_SIZE },
2868 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2869 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2870 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2871 { set_powered, false, MGMT_SETTING_SIZE },
2872 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2873 { set_connectable, false, MGMT_SETTING_SIZE },
2874 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2875 { set_pairable, false, MGMT_SETTING_SIZE },
2876 { set_link_security, false, MGMT_SETTING_SIZE },
2877 { set_ssp, false, MGMT_SETTING_SIZE },
2878 { set_hs, false, MGMT_SETTING_SIZE },
2879 { set_le, false, MGMT_SETTING_SIZE },
2880 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2881 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2882 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2883 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2884 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2885 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2886 { disconnect, false, MGMT_DISCONNECT_SIZE },
2887 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2888 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2889 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2890 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2891 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2892 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2893 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2894 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2895 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2896 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2897 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2898 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2899 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2900 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2901 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2902 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2903 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2904 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2905 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002906 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002907};
2908
2909
Johan Hedberg03811012010-12-08 00:21:06 +02002910int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2911{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002912 void *buf;
2913 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002914 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002915 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002916 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002917 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002918 int err;
2919
2920 BT_DBG("got %zu bytes", msglen);
2921
2922 if (msglen < sizeof(*hdr))
2923 return -EINVAL;
2924
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002925 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002926 if (!buf)
2927 return -ENOMEM;
2928
2929 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2930 err = -EFAULT;
2931 goto done;
2932 }
2933
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002934 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002935 opcode = __le16_to_cpu(hdr->opcode);
2936 index = __le16_to_cpu(hdr->index);
2937 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002938
2939 if (len != msglen - sizeof(*hdr)) {
2940 err = -EINVAL;
2941 goto done;
2942 }
2943
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002944 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002945 hdev = hci_dev_get(index);
2946 if (!hdev) {
2947 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002948 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002949 goto done;
2950 }
2951 }
2952
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002953 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002954 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002955 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002956 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002958 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002959 }
2960
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002961 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002962 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002963 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002964 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002965 goto done;
2966 }
2967
Johan Hedbergbe22b542012-03-01 22:24:41 +02002968 handler = &mgmt_handlers[opcode];
2969
2970 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002971 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002972 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002973 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002974 goto done;
2975 }
2976
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002977 if (hdev)
2978 mgmt_init_hdev(sk, hdev);
2979
2980 cp = buf + sizeof(*hdr);
2981
Johan Hedbergbe22b542012-03-01 22:24:41 +02002982 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002983 if (err < 0)
2984 goto done;
2985
Johan Hedberg03811012010-12-08 00:21:06 +02002986 err = msglen;
2987
2988done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002989 if (hdev)
2990 hci_dev_put(hdev);
2991
Johan Hedberg03811012010-12-08 00:21:06 +02002992 kfree(buf);
2993 return err;
2994}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002995
Johan Hedbergb24752f2011-11-03 14:40:33 +02002996static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2997{
2998 u8 *status = data;
2999
3000 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3001 mgmt_pending_remove(cmd);
3002}
3003
Johan Hedberg744cf192011-11-08 20:40:14 +02003004int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003005{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003006 if (!mgmt_valid_hdev(hdev))
3007 return -ENOTSUPP;
3008
Johan Hedberg744cf192011-11-08 20:40:14 +02003009 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003010}
3011
Johan Hedberg744cf192011-11-08 20:40:14 +02003012int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003013{
Johan Hedberg5f159032012-03-02 03:13:19 +02003014 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003015
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003016 if (!mgmt_valid_hdev(hdev))
3017 return -ENOTSUPP;
3018
Johan Hedberg744cf192011-11-08 20:40:14 +02003019 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003020
Johan Hedberg744cf192011-11-08 20:40:14 +02003021 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003022}
3023
Johan Hedberg73f22f62010-12-29 16:00:25 +02003024struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003025 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003026 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003027 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003028};
3029
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003030static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003031{
Johan Hedberg73f22f62010-12-29 16:00:25 +02003032 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003033
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003034 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003035
3036 list_del(&cmd->list);
3037
3038 if (match->sk == NULL) {
3039 match->sk = cmd->sk;
3040 sock_hold(match->sk);
3041 }
3042
3043 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003044}
Johan Hedberg5add6af2010-12-16 10:00:37 +02003045
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003046static int set_bredr_scan(struct hci_dev *hdev)
3047{
3048 u8 scan = 0;
3049
3050 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3051 scan |= SCAN_PAGE;
3052 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3053 scan |= SCAN_INQUIRY;
3054
3055 if (!scan)
3056 return 0;
3057
3058 return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3059}
3060
Johan Hedberg744cf192011-11-08 20:40:14 +02003061int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003062{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003063 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003064 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003065
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003066 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3067 return 0;
3068
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003069 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02003070
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003071 if (powered) {
Johan Hedbergf0ff92f2013-01-27 08:32:00 -06003072 u8 link_sec;
3073
Johan Hedberg6b4b73e2012-10-25 00:09:52 +03003074 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3075 !lmp_host_ssp_capable(hdev)) {
Andrzej Kaczmarek3d1cbdd2012-08-29 10:02:08 +02003076 u8 ssp = 1;
3077
3078 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
3079 }
3080
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003081 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
3082 struct hci_cp_write_le_host_supported cp;
3083
3084 cp.le = 1;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02003085 cp.simul = lmp_le_br_capable(hdev);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003086
Johan Hedberg430a61b2012-10-25 00:09:53 +03003087 /* Check first if we already have the right
3088 * host state (host features set)
3089 */
Gustavo Padovanffa88e02012-11-23 16:50:51 -02003090 if (cp.le != lmp_host_le_capable(hdev) ||
3091 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg430a61b2012-10-25 00:09:53 +03003092 hci_send_cmd(hdev,
3093 HCI_OP_WRITE_LE_HOST_SUPPORTED,
3094 sizeof(cp), &cp);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003095 }
3096
Johan Hedbergf0ff92f2013-01-27 08:32:00 -06003097 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3098 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
3099 hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE,
3100 sizeof(link_sec), &link_sec);
3101
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003102 if (lmp_bredr_capable(hdev)) {
3103 set_bredr_scan(hdev);
3104 update_class(hdev);
3105 update_name(hdev, hdev->dev_name);
3106 update_eir(hdev);
3107 }
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003108 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02003109 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedbergfe038882013-01-16 16:15:34 +02003110 u8 zero_cod[] = { 0, 0, 0 };
3111
Johan Hedberg744cf192011-11-08 20:40:14 +02003112 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergfe038882013-01-16 16:15:34 +02003113
3114 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3115 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3116 zero_cod, sizeof(zero_cod), NULL);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003117 }
3118
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003119 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003120
3121 if (match.sk)
3122 sock_put(match.sk);
3123
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003124 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003125}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003126
Johan Hedberg744cf192011-11-08 20:40:14 +02003127int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003128{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003129 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003130 bool changed = false;
3131 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003132
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003133 if (discoverable) {
3134 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3135 changed = true;
3136 } else {
3137 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3138 changed = true;
3139 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003140
Johan Hedberged9b5f22012-02-21 20:47:06 +02003141 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003142 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003143
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003144 if (changed)
3145 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003146
Johan Hedberg73f22f62010-12-29 16:00:25 +02003147 if (match.sk)
3148 sock_put(match.sk);
3149
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003150 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003151}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003152
Johan Hedberg744cf192011-11-08 20:40:14 +02003153int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003154{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003155 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003156 bool changed = false;
3157 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003158
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003159 if (connectable) {
3160 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3161 changed = true;
3162 } else {
3163 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3164 changed = true;
3165 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003166
Johan Hedberged9b5f22012-02-21 20:47:06 +02003167 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003168 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003169
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003170 if (changed)
3171 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003172
3173 if (match.sk)
3174 sock_put(match.sk);
3175
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003176 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003177}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003178
Johan Hedberg744cf192011-11-08 20:40:14 +02003179int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003180{
Johan Hedbergca69b792011-11-11 18:10:00 +02003181 u8 mgmt_err = mgmt_status(status);
3182
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003183 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003184 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003185 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003186
3187 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003188 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003189 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003190
3191 return 0;
3192}
3193
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003194int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3195 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003196{
Johan Hedberg86742e12011-11-07 23:13:38 +02003197 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003198
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003199 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003200
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003201 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003202 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003203 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003204 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003205 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003206 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003207
Johan Hedberg744cf192011-11-08 20:40:14 +02003208 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003209}
Johan Hedbergf7520542011-01-20 12:34:39 +02003210
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003211int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3212{
3213 struct mgmt_ev_new_long_term_key ev;
3214
3215 memset(&ev, 0, sizeof(ev));
3216
3217 ev.store_hint = persistent;
3218 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003219 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003220 ev.key.authenticated = key->authenticated;
3221 ev.key.enc_size = key->enc_size;
3222 ev.key.ediv = key->ediv;
3223
3224 if (key->type == HCI_SMP_LTK)
3225 ev.key.master = 1;
3226
3227 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3228 memcpy(ev.key.val, key->val, sizeof(key->val));
3229
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003230 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3231 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003232}
3233
Johan Hedbergafc747a2012-01-15 18:11:07 +02003234int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003235 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3236 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003237{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003238 char buf[512];
3239 struct mgmt_ev_device_connected *ev = (void *) buf;
3240 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003241
Johan Hedbergb644ba32012-01-17 21:48:47 +02003242 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003243 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003244
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003245 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003246
Johan Hedbergb644ba32012-01-17 21:48:47 +02003247 if (name_len > 0)
3248 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003249 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003250
3251 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003252 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003253 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003254
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003255 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003256
3257 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003258 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003259}
3260
Johan Hedberg8962ee72011-01-20 12:40:27 +02003261static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3262{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003263 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003264 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003265 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003266
Johan Hedberg88c3df12012-02-09 14:27:38 +02003267 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3268 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003269
Johan Hedbergaee9b212012-02-18 15:07:59 +02003270 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003271 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003272
3273 *sk = cmd->sk;
3274 sock_hold(*sk);
3275
Johan Hedberga664b5b2011-02-19 12:06:02 -03003276 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003277}
3278
Johan Hedberg124f6e32012-02-09 13:50:12 +02003279static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003280{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003281 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003282 struct mgmt_cp_unpair_device *cp = cmd->param;
3283 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003284
3285 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003286 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3287 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003288
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003289 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3290
Johan Hedbergaee9b212012-02-18 15:07:59 +02003291 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003292
3293 mgmt_pending_remove(cmd);
3294}
3295
Johan Hedbergafc747a2012-01-15 18:11:07 +02003296int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003297 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003298{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003299 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003300 struct sock *sk = NULL;
3301 int err;
3302
Johan Hedberg744cf192011-11-08 20:40:14 +02003303 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003304
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003305 bacpy(&ev.addr.bdaddr, bdaddr);
3306 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3307 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003308
Johan Hedbergafc747a2012-01-15 18:11:07 +02003309 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003310 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003311
3312 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003313 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003314
Johan Hedberg124f6e32012-02-09 13:50:12 +02003315 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003316 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003317
Johan Hedberg8962ee72011-01-20 12:40:27 +02003318 return err;
3319}
3320
Johan Hedberg88c3df12012-02-09 14:27:38 +02003321int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003322 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003323{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003324 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003325 struct pending_cmd *cmd;
3326 int err;
3327
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003328 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3329 hdev);
3330
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003331 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003332 if (!cmd)
3333 return -ENOENT;
3334
Johan Hedberg88c3df12012-02-09 14:27:38 +02003335 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003336 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003337
Johan Hedberg88c3df12012-02-09 14:27:38 +02003338 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003339 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003340
Johan Hedberga664b5b2011-02-19 12:06:02 -03003341 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003342
3343 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003344}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003345
Johan Hedberg48264f02011-11-09 13:58:58 +02003346int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003347 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003348{
3349 struct mgmt_ev_connect_failed ev;
3350
Johan Hedberg4c659c32011-11-07 23:13:39 +02003351 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003352 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003353 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003354
Johan Hedberg744cf192011-11-08 20:40:14 +02003355 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003356}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003357
Johan Hedberg744cf192011-11-08 20:40:14 +02003358int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003359{
3360 struct mgmt_ev_pin_code_request ev;
3361
Johan Hedbergd8457692012-02-17 14:24:57 +02003362 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003363 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003364 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003365
Johan Hedberg744cf192011-11-08 20:40:14 +02003366 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003367 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003368}
3369
Johan Hedberg744cf192011-11-08 20:40:14 +02003370int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003371 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003372{
3373 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003374 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003375 int err;
3376
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003377 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003378 if (!cmd)
3379 return -ENOENT;
3380
Johan Hedbergd8457692012-02-17 14:24:57 +02003381 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003382 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003383
Johan Hedbergaee9b212012-02-18 15:07:59 +02003384 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003385 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003386
Johan Hedberga664b5b2011-02-19 12:06:02 -03003387 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003388
3389 return err;
3390}
3391
Johan Hedberg744cf192011-11-08 20:40:14 +02003392int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003393 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003394{
3395 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003396 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003397 int err;
3398
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003399 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003400 if (!cmd)
3401 return -ENOENT;
3402
Johan Hedbergd8457692012-02-17 14:24:57 +02003403 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003404 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003405
Johan Hedbergaee9b212012-02-18 15:07:59 +02003406 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003407 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003408
Johan Hedberga664b5b2011-02-19 12:06:02 -03003409 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003410
3411 return err;
3412}
Johan Hedberga5c29682011-02-19 12:05:57 -03003413
Johan Hedberg744cf192011-11-08 20:40:14 +02003414int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003415 u8 link_type, u8 addr_type, __le32 value,
3416 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003417{
3418 struct mgmt_ev_user_confirm_request ev;
3419
Johan Hedberg744cf192011-11-08 20:40:14 +02003420 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003421
Johan Hedberg272d90d2012-02-09 15:26:12 +02003422 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003423 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003424 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003425 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003426
Johan Hedberg744cf192011-11-08 20:40:14 +02003427 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003428 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003429}
3430
Johan Hedberg272d90d2012-02-09 15:26:12 +02003431int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003432 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003433{
3434 struct mgmt_ev_user_passkey_request ev;
3435
3436 BT_DBG("%s", hdev->name);
3437
Johan Hedberg272d90d2012-02-09 15:26:12 +02003438 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003439 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003440
3441 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003442 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003443}
3444
Brian Gix0df4c182011-11-16 13:53:13 -08003445static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003446 u8 link_type, u8 addr_type, u8 status,
3447 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003448{
3449 struct pending_cmd *cmd;
3450 struct mgmt_rp_user_confirm_reply rp;
3451 int err;
3452
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003453 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003454 if (!cmd)
3455 return -ENOENT;
3456
Johan Hedberg272d90d2012-02-09 15:26:12 +02003457 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003458 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003459 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003460 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003461
Johan Hedberga664b5b2011-02-19 12:06:02 -03003462 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003463
3464 return err;
3465}
3466
Johan Hedberg744cf192011-11-08 20:40:14 +02003467int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003468 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003469{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003470 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003471 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003472}
3473
Johan Hedberg272d90d2012-02-09 15:26:12 +02003474int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003475 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003476{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003477 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003478 status,
3479 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003480}
Johan Hedberg2a611692011-02-19 12:06:00 -03003481
Brian Gix604086b2011-11-23 08:28:33 -08003482int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003483 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003484{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003485 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003486 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003487}
3488
Johan Hedberg272d90d2012-02-09 15:26:12 +02003489int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003490 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003491{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003492 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003493 status,
3494 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003495}
3496
Johan Hedberg92a25252012-09-06 18:39:26 +03003497int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3498 u8 link_type, u8 addr_type, u32 passkey,
3499 u8 entered)
3500{
3501 struct mgmt_ev_passkey_notify ev;
3502
3503 BT_DBG("%s", hdev->name);
3504
3505 bacpy(&ev.addr.bdaddr, bdaddr);
3506 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3507 ev.passkey = __cpu_to_le32(passkey);
3508 ev.entered = entered;
3509
3510 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3511}
3512
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003513int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003514 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003515{
3516 struct mgmt_ev_auth_failed ev;
3517
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003518 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003519 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003520 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003521
Johan Hedberg744cf192011-11-08 20:40:14 +02003522 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003523}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003524
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003525int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3526{
3527 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003528 bool changed = false;
3529 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003530
3531 if (status) {
3532 u8 mgmt_err = mgmt_status(status);
3533 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003534 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003535 return 0;
3536 }
3537
Johan Hedberg47990ea2012-02-22 11:58:37 +02003538 if (test_bit(HCI_AUTH, &hdev->flags)) {
3539 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3540 changed = true;
3541 } else {
3542 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3543 changed = true;
3544 }
3545
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003546 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003547 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003548
Johan Hedberg47990ea2012-02-22 11:58:37 +02003549 if (changed)
3550 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003551
3552 if (match.sk)
3553 sock_put(match.sk);
3554
3555 return err;
3556}
3557
Johan Hedbergcacaf522012-02-21 00:52:42 +02003558static int clear_eir(struct hci_dev *hdev)
3559{
3560 struct hci_cp_write_eir cp;
3561
Johan Hedberg976eb202012-10-24 21:12:01 +03003562 if (!lmp_ext_inq_capable(hdev))
Johan Hedbergcacaf522012-02-21 00:52:42 +02003563 return 0;
3564
Johan Hedbergc80da272012-02-22 15:38:48 +02003565 memset(hdev->eir, 0, sizeof(hdev->eir));
3566
Johan Hedbergcacaf522012-02-21 00:52:42 +02003567 memset(&cp, 0, sizeof(cp));
3568
3569 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3570}
3571
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003572int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003573{
3574 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003575 bool changed = false;
3576 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003577
3578 if (status) {
3579 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003580
3581 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003582 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003583 err = new_settings(hdev, NULL);
3584
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003585 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3586 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003587
3588 return err;
3589 }
3590
3591 if (enable) {
3592 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3593 changed = true;
3594 } else {
3595 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3596 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003597 }
3598
3599 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3600
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003601 if (changed)
3602 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003603
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003604 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003605 sock_put(match.sk);
3606
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003607 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3608 update_eir(hdev);
3609 else
3610 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003611
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003612 return err;
3613}
3614
Johan Hedberg90e70452012-02-23 23:09:40 +02003615static void class_rsp(struct pending_cmd *cmd, void *data)
3616{
3617 struct cmd_lookup *match = data;
3618
3619 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003620 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003621
3622 list_del(&cmd->list);
3623
3624 if (match->sk == NULL) {
3625 match->sk = cmd->sk;
3626 sock_hold(match->sk);
3627 }
3628
3629 mgmt_pending_free(cmd);
3630}
3631
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003632int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003633 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003634{
Johan Hedberg90e70452012-02-23 23:09:40 +02003635 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3636 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003637
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003638 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3639
Johan Hedberg90e70452012-02-23 23:09:40 +02003640 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3641 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3642 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3643
3644 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003645 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3646 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003647
3648 if (match.sk)
3649 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003650
3651 return err;
3652}
3653
Johan Hedberg744cf192011-11-08 20:40:14 +02003654int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003655{
3656 struct pending_cmd *cmd;
3657 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003658 bool changed = false;
3659 int err = 0;
3660
3661 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3662 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3663 changed = true;
3664 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003665
3666 memset(&ev, 0, sizeof(ev));
3667 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003668 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003669
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003670 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003671 if (!cmd)
3672 goto send_event;
3673
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003674 /* Always assume that either the short or the complete name has
3675 * changed if there was a pending mgmt command */
3676 changed = true;
3677
Johan Hedbergb312b1612011-03-16 14:29:37 +02003678 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003679 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003680 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003681 goto failed;
3682 }
3683
Johan Hedbergaee9b212012-02-18 15:07:59 +02003684 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003685 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003686 if (err < 0)
3687 goto failed;
3688
3689send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003690 if (changed)
3691 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003692 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003693
Johan Hedberg1225a6b2012-10-25 00:09:54 +03003694 /* EIR is taken care of separately when powering on the
3695 * adapter so only update them here if this is a name change
3696 * unrelated to power on.
3697 */
3698 if (!test_bit(HCI_INIT, &hdev->flags))
3699 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003700
3701failed:
3702 if (cmd)
3703 mgmt_pending_remove(cmd);
3704 return err;
3705}
Szymon Jancc35938b2011-03-22 13:12:21 +01003706
Johan Hedberg744cf192011-11-08 20:40:14 +02003707int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003708 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003709{
3710 struct pending_cmd *cmd;
3711 int err;
3712
Johan Hedberg744cf192011-11-08 20:40:14 +02003713 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003714
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003715 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003716 if (!cmd)
3717 return -ENOENT;
3718
3719 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003720 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3721 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003722 } else {
3723 struct mgmt_rp_read_local_oob_data rp;
3724
3725 memcpy(rp.hash, hash, sizeof(rp.hash));
3726 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3727
Johan Hedberg744cf192011-11-08 20:40:14 +02003728 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003729 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3730 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003731 }
3732
3733 mgmt_pending_remove(cmd);
3734
3735 return err;
3736}
Johan Hedberge17acd42011-03-30 23:57:16 +03003737
Johan Hedberg06199cf2012-02-22 16:37:11 +02003738int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3739{
3740 struct cmd_lookup match = { NULL, hdev };
3741 bool changed = false;
3742 int err = 0;
3743
3744 if (status) {
3745 u8 mgmt_err = mgmt_status(status);
3746
3747 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003748 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003749 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003750
Szymon Jancd97dcb62012-03-16 16:02:56 +01003751 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3752 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003753
3754 return err;
3755 }
3756
3757 if (enable) {
3758 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3759 changed = true;
3760 } else {
3761 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3762 changed = true;
3763 }
3764
3765 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3766
3767 if (changed)
3768 err = new_settings(hdev, match.sk);
3769
3770 if (match.sk)
3771 sock_put(match.sk);
3772
3773 return err;
3774}
3775
Johan Hedberg48264f02011-11-09 13:58:58 +02003776int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003777 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3778 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003779{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003780 char buf[512];
3781 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003782 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003783
Johan Hedberg1dc06092012-01-15 21:01:23 +02003784 /* Leave 5 bytes for a potential CoD field */
3785 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003786 return -EINVAL;
3787
Johan Hedberg1dc06092012-01-15 21:01:23 +02003788 memset(buf, 0, sizeof(buf));
3789
Johan Hedberge319d2e2012-01-15 19:51:59 +02003790 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003791 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003792 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003793 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303794 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003795 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303796 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003797
Johan Hedberg1dc06092012-01-15 21:01:23 +02003798 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003799 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003800
Johan Hedberg1dc06092012-01-15 21:01:23 +02003801 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3802 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003803 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003804
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003805 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003806 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003807
Johan Hedberge319d2e2012-01-15 19:51:59 +02003808 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003809}
Johan Hedberga88a9652011-03-30 13:18:12 +03003810
Johan Hedbergb644ba32012-01-17 21:48:47 +02003811int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003812 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003813{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003814 struct mgmt_ev_device_found *ev;
3815 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3816 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003817
Johan Hedbergb644ba32012-01-17 21:48:47 +02003818 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003819
Johan Hedbergb644ba32012-01-17 21:48:47 +02003820 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003821
Johan Hedbergb644ba32012-01-17 21:48:47 +02003822 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003823 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003824 ev->rssi = rssi;
3825
3826 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003827 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003828
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003829 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003830
Johan Hedberg053c7e02012-02-04 00:06:00 +02003831 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003832 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003833}
Johan Hedberg314b2382011-04-27 10:29:57 -04003834
Andre Guedes7a135102011-11-09 17:14:25 -03003835int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003836{
3837 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003838 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003839 int err;
3840
Andre Guedes203159d2012-02-13 15:41:01 -03003841 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3842
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003843 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003844 if (!cmd)
3845 return -ENOENT;
3846
Johan Hedbergf808e162012-02-19 12:52:07 +02003847 type = hdev->discovery.type;
3848
3849 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003850 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003851 mgmt_pending_remove(cmd);
3852
3853 return err;
3854}
3855
Andre Guedese6d465c2011-11-09 17:14:26 -03003856int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3857{
3858 struct pending_cmd *cmd;
3859 int err;
3860
3861 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3862 if (!cmd)
3863 return -ENOENT;
3864
Johan Hedbergd9306502012-02-20 23:25:18 +02003865 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003866 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003867 mgmt_pending_remove(cmd);
3868
3869 return err;
3870}
Johan Hedberg314b2382011-04-27 10:29:57 -04003871
Johan Hedberg744cf192011-11-08 20:40:14 +02003872int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003873{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003874 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003875 struct pending_cmd *cmd;
3876
Andre Guedes343fb142011-11-22 17:14:19 -03003877 BT_DBG("%s discovering %u", hdev->name, discovering);
3878
Johan Hedberg164a6e72011-11-01 17:06:44 +02003879 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003880 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003881 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003882 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003883
3884 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003885 u8 type = hdev->discovery.type;
3886
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003887 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3888 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003889 mgmt_pending_remove(cmd);
3890 }
3891
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003892 memset(&ev, 0, sizeof(ev));
3893 ev.type = hdev->discovery.type;
3894 ev.discovering = discovering;
3895
3896 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003897}
Antti Julku5e762442011-08-25 16:48:02 +03003898
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003899int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003900{
3901 struct pending_cmd *cmd;
3902 struct mgmt_ev_device_blocked ev;
3903
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003904 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003905
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003906 bacpy(&ev.addr.bdaddr, bdaddr);
3907 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003908
Johan Hedberg744cf192011-11-08 20:40:14 +02003909 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003910 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003911}
3912
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003913int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003914{
3915 struct pending_cmd *cmd;
3916 struct mgmt_ev_device_unblocked ev;
3917
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003918 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003919
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003920 bacpy(&ev.addr.bdaddr, bdaddr);
3921 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003922
Johan Hedberg744cf192011-11-08 20:40:14 +02003923 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003924 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003925}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003926
3927module_param(enable_hs, bool, 0644);
3928MODULE_PARM_DESC(enable_hs, "Enable High Speed support");