blob: 1e906d8d86ac3e5782464d785901d66a666a6402 [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 Hedberg23b3b132012-09-06 18:39:27 +030038#define MGMT_REVISION 2
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 Hedberg80a1e1d2011-03-28 14:07:23 +0300438static void create_eir(struct hci_dev *hdev, u8 *data)
439{
440 u8 *ptr = data;
441 u16 eir_len = 0;
442 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
443 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200444 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300445 size_t name_len;
446
447 name_len = strlen(hdev->dev_name);
448
449 if (name_len > 0) {
450 /* EIR Data type */
451 if (name_len > 48) {
452 name_len = 48;
453 ptr[1] = EIR_NAME_SHORT;
454 } else
455 ptr[1] = EIR_NAME_COMPLETE;
456
457 /* EIR Data length */
458 ptr[0] = name_len + 1;
459
460 memcpy(ptr + 2, hdev->dev_name, name_len);
461
462 eir_len += (name_len + 2);
463 ptr += (name_len + 2);
464 }
465
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100466 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700467 ptr[0] = 2;
468 ptr[1] = EIR_TX_POWER;
469 ptr[2] = (u8) hdev->inq_tx_power;
470
471 eir_len += 3;
472 ptr += 3;
473 }
474
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700475 if (hdev->devid_source > 0) {
476 ptr[0] = 9;
477 ptr[1] = EIR_DEVICE_ID;
478
479 put_unaligned_le16(hdev->devid_source, ptr + 2);
480 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
481 put_unaligned_le16(hdev->devid_product, ptr + 6);
482 put_unaligned_le16(hdev->devid_version, ptr + 8);
483
484 eir_len += 10;
485 ptr += 10;
486 }
487
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300488 memset(uuid16_list, 0, sizeof(uuid16_list));
489
490 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200491 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300492 u16 uuid16;
493
Johan Hedberg83be8ec2013-01-27 00:31:29 +0200494 if (uuid->size != 16)
495 continue;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300496
Johan Hedberg83be8ec2013-01-27 00:31:29 +0200497 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300498 if (uuid16 < 0x1100)
499 continue;
500
501 if (uuid16 == PNP_INFO_SVCLASS_ID)
502 continue;
503
504 /* Stop if not enough space to put next UUID */
505 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
506 truncated = 1;
507 break;
508 }
509
510 /* Check for duplicates */
511 for (i = 0; uuid16_list[i] != 0; i++)
512 if (uuid16_list[i] == uuid16)
513 break;
514
515 if (uuid16_list[i] == 0) {
516 uuid16_list[i] = uuid16;
517 eir_len += sizeof(u16);
518 }
519 }
520
521 if (uuid16_list[0] != 0) {
522 u8 *length = ptr;
523
524 /* EIR Data type */
525 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
526
527 ptr += 2;
528 eir_len += 2;
529
530 for (i = 0; uuid16_list[i] != 0; i++) {
531 *ptr++ = (uuid16_list[i] & 0x00ff);
532 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
533 }
534
535 /* EIR Data length */
536 *length = (i * sizeof(u16)) + 1;
537 }
538}
539
540static int update_eir(struct hci_dev *hdev)
541{
542 struct hci_cp_write_eir cp;
543
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200544 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200545 return 0;
546
Johan Hedberg976eb202012-10-24 21:12:01 +0300547 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548 return 0;
549
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200550 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300551 return 0;
552
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200553 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300554 return 0;
555
556 memset(&cp, 0, sizeof(cp));
557
558 create_eir(hdev, cp.data);
559
560 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
561 return 0;
562
563 memcpy(hdev->eir, cp.data, sizeof(cp.data));
564
565 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
566}
567
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200568static u8 get_service_classes(struct hci_dev *hdev)
569{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300570 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200571 u8 val = 0;
572
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300573 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200575
576 return val;
577}
578
579static int update_class(struct hci_dev *hdev)
580{
581 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200582 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200583
584 BT_DBG("%s", hdev->name);
585
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200586 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200587 return 0;
588
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200589 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200590 return 0;
591
592 cod[0] = hdev->minor_class;
593 cod[1] = hdev->major_class;
594 cod[2] = get_service_classes(hdev);
595
596 if (memcmp(cod, hdev->dev_class, 3) == 0)
597 return 0;
598
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200599 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
600 if (err == 0)
601 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
602
603 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200604}
605
Johan Hedberg7d785252011-12-15 00:47:39 +0200606static void service_cache_off(struct work_struct *work)
607{
608 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300609 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200610
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200611 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200612 return;
613
614 hci_dev_lock(hdev);
615
616 update_eir(hdev);
617 update_class(hdev);
618
619 hci_dev_unlock(hdev);
620}
621
Johan Hedberg6a919082012-02-28 06:17:26 +0200622static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200623{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200624 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200625 return;
626
Johan Hedberg4f87da82012-03-02 19:55:56 +0200627 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200628
Johan Hedberg4f87da82012-03-02 19:55:56 +0200629 /* Non-mgmt controlled devices get this bit set
630 * implicitly so that pairing works for them, however
631 * for mgmt we require user-space to explicitly enable
632 * it
633 */
634 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200635}
636
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200637static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300638 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200639{
640 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200641
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200642 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200643
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300644 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 memset(&rp, 0, sizeof(rp));
647
Johan Hedberg03811012010-12-08 00:21:06 +0200648 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200649
650 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200651 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200652
653 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
654 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
655
656 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200657
658 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200659 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200660
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300661 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200662
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200663 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300664 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200665}
666
667static void mgmt_pending_free(struct pending_cmd *cmd)
668{
669 sock_put(cmd->sk);
670 kfree(cmd->param);
671 kfree(cmd);
672}
673
674static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300675 struct hci_dev *hdev, void *data,
676 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200677{
678 struct pending_cmd *cmd;
679
Andre Guedes12b94562012-06-07 19:05:45 -0300680 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200681 if (!cmd)
682 return NULL;
683
684 cmd->opcode = opcode;
685 cmd->index = hdev->id;
686
Andre Guedes12b94562012-06-07 19:05:45 -0300687 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200688 if (!cmd->param) {
689 kfree(cmd);
690 return NULL;
691 }
692
693 if (data)
694 memcpy(cmd->param, data, len);
695
696 cmd->sk = sk;
697 sock_hold(sk);
698
699 list_add(&cmd->list, &hdev->mgmt_pending);
700
701 return cmd;
702}
703
704static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300705 void (*cb)(struct pending_cmd *cmd,
706 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300707 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200708{
709 struct list_head *p, *n;
710
711 list_for_each_safe(p, n, &hdev->mgmt_pending) {
712 struct pending_cmd *cmd;
713
714 cmd = list_entry(p, struct pending_cmd, list);
715
716 if (opcode > 0 && cmd->opcode != opcode)
717 continue;
718
719 cb(cmd, data);
720 }
721}
722
723static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
724{
725 struct pending_cmd *cmd;
726
727 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
728 if (cmd->opcode == opcode)
729 return cmd;
730 }
731
732 return NULL;
733}
734
735static void mgmt_pending_remove(struct pending_cmd *cmd)
736{
737 list_del(&cmd->list);
738 mgmt_pending_free(cmd);
739}
740
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200741static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200742{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200743 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200744
Johan Hedbergaee9b212012-02-18 15:07:59 +0200745 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300746 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200747}
748
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200749static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300750 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200751{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300752 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200753 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200754 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200755
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200756 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200757
Johan Hedberga7e80f22013-01-09 16:05:19 +0200758 if (cp->val != 0x00 && cp->val != 0x01)
759 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
760 MGMT_STATUS_INVALID_PARAMS);
761
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300762 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200763
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100764 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
765 cancel_delayed_work(&hdev->power_off);
766
767 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200768 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
769 data, len);
770 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100771 goto failed;
772 }
773 }
774
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200775 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200776 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200777 goto failed;
778 }
779
780 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200781 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300782 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 goto failed;
784 }
785
786 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
787 if (!cmd) {
788 err = -ENOMEM;
789 goto failed;
790 }
791
792 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200793 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200794 else
Johan Hedberg19202572013-01-14 22:33:51 +0200795 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200796
797 err = 0;
798
799failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300800 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200801 return err;
802}
803
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300804static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
805 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200806{
807 struct sk_buff *skb;
808 struct mgmt_hdr *hdr;
809
Andre Guedes790eff42012-06-07 19:05:46 -0300810 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200811 if (!skb)
812 return -ENOMEM;
813
814 hdr = (void *) skb_put(skb, sizeof(*hdr));
815 hdr->opcode = cpu_to_le16(event);
816 if (hdev)
817 hdr->index = cpu_to_le16(hdev->id);
818 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530819 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200820 hdr->len = cpu_to_le16(data_len);
821
822 if (data)
823 memcpy(skb_put(skb, data_len), data, data_len);
824
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100825 /* Time stamp */
826 __net_timestamp(skb);
827
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200828 hci_send_to_control(skb, skip_sk);
829 kfree_skb(skb);
830
831 return 0;
832}
833
834static int new_settings(struct hci_dev *hdev, struct sock *skip)
835{
836 __le32 ev;
837
838 ev = cpu_to_le32(get_current_settings(hdev));
839
840 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
841}
842
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200843static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300844 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200845{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300846 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200847 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200848 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200849 u8 scan;
850 int err;
851
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200852 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200853
Johan Hedberg33c525c2012-10-24 21:11:58 +0300854 if (!lmp_bredr_capable(hdev))
855 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
856 MGMT_STATUS_NOT_SUPPORTED);
857
Johan Hedberga7e80f22013-01-09 16:05:19 +0200858 if (cp->val != 0x00 && cp->val != 0x01)
859 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
860 MGMT_STATUS_INVALID_PARAMS);
861
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700862 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100863 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200864 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300865 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200866
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300867 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200868
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200869 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200870 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300871 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200872 goto failed;
873 }
874
875 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300876 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200877 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300878 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200879 goto failed;
880 }
881
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200882 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200883 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300884 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200885 goto failed;
886 }
887
888 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200889 bool changed = false;
890
891 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
892 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
893 changed = true;
894 }
895
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200896 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200897 if (err < 0)
898 goto failed;
899
900 if (changed)
901 err = new_settings(hdev, sk);
902
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200903 goto failed;
904 }
905
906 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100907 if (hdev->discov_timeout > 0) {
908 cancel_delayed_work(&hdev->discov_off);
909 hdev->discov_timeout = 0;
910 }
911
912 if (cp->val && timeout > 0) {
913 hdev->discov_timeout = timeout;
914 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
915 msecs_to_jiffies(hdev->discov_timeout * 1000));
916 }
917
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200918 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200919 goto failed;
920 }
921
922 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
923 if (!cmd) {
924 err = -ENOMEM;
925 goto failed;
926 }
927
928 scan = SCAN_PAGE;
929
930 if (cp->val)
931 scan |= SCAN_INQUIRY;
932 else
933 cancel_delayed_work(&hdev->discov_off);
934
935 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
936 if (err < 0)
937 mgmt_pending_remove(cmd);
938
Johan Hedberg03811012010-12-08 00:21:06 +0200939 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200940 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200941
942failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300943 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200944 return err;
945}
946
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200947static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300948 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200949{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300950 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200951 struct pending_cmd *cmd;
952 u8 scan;
953 int err;
954
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200955 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200956
Johan Hedberg33c525c2012-10-24 21:11:58 +0300957 if (!lmp_bredr_capable(hdev))
958 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
959 MGMT_STATUS_NOT_SUPPORTED);
960
Johan Hedberga7e80f22013-01-09 16:05:19 +0200961 if (cp->val != 0x00 && cp->val != 0x01)
962 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
963 MGMT_STATUS_INVALID_PARAMS);
964
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300965 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200967 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200968 bool changed = false;
969
970 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
971 changed = true;
972
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200973 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200974 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200975 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200976 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
977 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
978 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200979
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200980 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200981 if (err < 0)
982 goto failed;
983
984 if (changed)
985 err = new_settings(hdev, sk);
986
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200987 goto failed;
988 }
989
990 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300991 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200992 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300993 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 goto failed;
995 }
996
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200997 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200998 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200999 goto failed;
1000 }
1001
1002 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1003 if (!cmd) {
1004 err = -ENOMEM;
1005 goto failed;
1006 }
1007
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001008 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001010 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011 scan = 0;
1012
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001013 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001014 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001015 cancel_delayed_work(&hdev->discov_off);
1016 }
1017
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001018 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1019 if (err < 0)
1020 mgmt_pending_remove(cmd);
1021
1022failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001023 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001024 return err;
1025}
1026
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001027static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001028 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001029{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001030 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001031 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001033 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
Johan Hedberga7e80f22013-01-09 16:05:19 +02001035 if (cp->val != 0x00 && cp->val != 0x01)
1036 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1037 MGMT_STATUS_INVALID_PARAMS);
1038
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001039 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
1041 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001042 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001044 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001045
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001046 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047 if (err < 0)
1048 goto failed;
1049
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001050 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001051
1052failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001053 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054 return err;
1055}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001056
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001057static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1058 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001059{
1060 struct mgmt_mode *cp = data;
1061 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001062 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001063 int err;
1064
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001065 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001066
Johan Hedberg33c525c2012-10-24 21:11:58 +03001067 if (!lmp_bredr_capable(hdev))
1068 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1069 MGMT_STATUS_NOT_SUPPORTED);
1070
Johan Hedberga7e80f22013-01-09 16:05:19 +02001071 if (cp->val != 0x00 && cp->val != 0x01)
1072 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1073 MGMT_STATUS_INVALID_PARAMS);
1074
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001075 hci_dev_lock(hdev);
1076
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001077 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001078 bool changed = false;
1079
1080 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001081 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001082 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1083 changed = true;
1084 }
1085
1086 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1087 if (err < 0)
1088 goto failed;
1089
1090 if (changed)
1091 err = new_settings(hdev, sk);
1092
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001093 goto failed;
1094 }
1095
1096 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001097 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001098 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001099 goto failed;
1100 }
1101
1102 val = !!cp->val;
1103
1104 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1105 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1106 goto failed;
1107 }
1108
1109 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1110 if (!cmd) {
1111 err = -ENOMEM;
1112 goto failed;
1113 }
1114
1115 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1116 if (err < 0) {
1117 mgmt_pending_remove(cmd);
1118 goto failed;
1119 }
1120
1121failed:
1122 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001123 return err;
1124}
1125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001126static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001127{
1128 struct mgmt_mode *cp = data;
1129 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001130 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001131 int err;
1132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001133 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001134
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001135 if (!lmp_ssp_capable(hdev))
1136 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1137 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001138
Johan Hedberga7e80f22013-01-09 16:05:19 +02001139 if (cp->val != 0x00 && cp->val != 0x01)
1140 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1141 MGMT_STATUS_INVALID_PARAMS);
1142
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001143 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001144
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001145 val = !!cp->val;
1146
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001147 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001148 bool changed = false;
1149
1150 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1151 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1152 changed = true;
1153 }
1154
1155 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1156 if (err < 0)
1157 goto failed;
1158
1159 if (changed)
1160 err = new_settings(hdev, sk);
1161
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001162 goto failed;
1163 }
1164
1165 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001166 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1167 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001168 goto failed;
1169 }
1170
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001171 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1172 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1173 goto failed;
1174 }
1175
1176 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1177 if (!cmd) {
1178 err = -ENOMEM;
1179 goto failed;
1180 }
1181
1182 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1183 if (err < 0) {
1184 mgmt_pending_remove(cmd);
1185 goto failed;
1186 }
1187
1188failed:
1189 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001190 return err;
1191}
1192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001193static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001194{
1195 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001197 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001198
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001199 if (!enable_hs)
1200 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001201 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001202
Johan Hedberga7e80f22013-01-09 16:05:19 +02001203 if (cp->val != 0x00 && cp->val != 0x01)
1204 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1205 MGMT_STATUS_INVALID_PARAMS);
1206
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001207 if (cp->val)
1208 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1209 else
1210 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001212 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001213}
1214
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001215static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001216{
1217 struct mgmt_mode *cp = data;
1218 struct hci_cp_write_le_host_supported hci_cp;
1219 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001220 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001221 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001223 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001224
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001225 if (!lmp_le_capable(hdev))
1226 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1227 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001228
Johan Hedberga7e80f22013-01-09 16:05:19 +02001229 if (cp->val != 0x00 && cp->val != 0x01)
1230 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1231 MGMT_STATUS_INVALID_PARAMS);
1232
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001233 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001234
1235 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001236 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001237
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001238 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001239 bool changed = false;
1240
1241 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1242 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1243 changed = true;
1244 }
1245
1246 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1247 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001248 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001249
1250 if (changed)
1251 err = new_settings(hdev, sk);
1252
Johan Hedberg1de028c2012-02-29 19:55:35 -08001253 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001254 }
1255
1256 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001257 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001258 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001259 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001260 }
1261
1262 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1263 if (!cmd) {
1264 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001265 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001266 }
1267
1268 memset(&hci_cp, 0, sizeof(hci_cp));
1269
1270 if (val) {
1271 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001272 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001273 }
1274
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001275 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1276 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301277 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001278 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001279
Johan Hedberg1de028c2012-02-29 19:55:35 -08001280unlock:
1281 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001282 return err;
1283}
1284
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001285static const u8 bluetooth_base_uuid[] = {
1286 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1287 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1288};
1289
1290static u8 get_uuid_size(const u8 *uuid)
1291{
1292 u32 val;
1293
1294 if (memcmp(uuid, bluetooth_base_uuid, 12))
1295 return 128;
1296
1297 val = get_unaligned_le32(&uuid[12]);
1298 if (val > 0xffff)
1299 return 32;
1300
1301 return 16;
1302}
1303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001304static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001305{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001306 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001307 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001308 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001309 int err;
1310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001311 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001313 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001314
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001315 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001316 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001317 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001318 goto failed;
1319 }
1320
Andre Guedes92c4c202012-06-07 19:05:44 -03001321 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001322 if (!uuid) {
1323 err = -ENOMEM;
1324 goto failed;
1325 }
1326
1327 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001328 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001329 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330
Johan Hedbergde66aa62013-01-27 00:31:27 +02001331 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001333 err = update_class(hdev);
1334 if (err < 0)
1335 goto failed;
1336
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001337 err = update_eir(hdev);
1338 if (err < 0)
1339 goto failed;
1340
Johan Hedberg90e70452012-02-23 23:09:40 +02001341 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001344 goto failed;
1345 }
1346
1347 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301348 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001349 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001350
1351failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001352 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001353 return err;
1354}
1355
Johan Hedberg24b78d02012-02-23 23:24:30 +02001356static bool enable_service_cache(struct hci_dev *hdev)
1357{
1358 if (!hdev_is_powered(hdev))
1359 return false;
1360
1361 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001362 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1363 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001364 return true;
1365 }
1366
1367 return false;
1368}
1369
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001370static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001371 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001372{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001373 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001374 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001375 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001376 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 +02001377 int err, found;
1378
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001379 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001380
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001381 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001382
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001383 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001384 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001385 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001386 goto unlock;
1387 }
1388
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001389 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1390 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001391
Johan Hedberg24b78d02012-02-23 23:24:30 +02001392 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001394 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001395 goto unlock;
1396 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001397
Johan Hedberg9246a862012-02-23 21:33:16 +02001398 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001399 }
1400
1401 found = 0;
1402
Johan Hedberg056341c2013-01-27 00:31:30 +02001403 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001404 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1405 continue;
1406
1407 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001408 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001409 found++;
1410 }
1411
1412 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001413 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001414 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001415 goto unlock;
1416 }
1417
Johan Hedberg9246a862012-02-23 21:33:16 +02001418update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001419 err = update_class(hdev);
1420 if (err < 0)
1421 goto unlock;
1422
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001423 err = update_eir(hdev);
1424 if (err < 0)
1425 goto unlock;
1426
Johan Hedberg90e70452012-02-23 23:09:40 +02001427 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001428 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001429 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001430 goto unlock;
1431 }
1432
1433 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301434 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001435 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001436
1437unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001438 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001439 return err;
1440}
1441
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001442static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001443 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001444{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001445 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001446 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447 int err;
1448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001450
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001451 if (!lmp_bredr_capable(hdev))
1452 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1453 MGMT_STATUS_NOT_SUPPORTED);
1454
1455 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags))
1456 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1457 MGMT_STATUS_BUSY);
1458
1459 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0)
1460 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1461 MGMT_STATUS_INVALID_PARAMS);
1462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001463 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001464
1465 hdev->major_class = cp->major;
1466 hdev->minor_class = cp->minor;
1467
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001468 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001469 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001470 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001471 goto unlock;
1472 }
1473
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001474 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001475 hci_dev_unlock(hdev);
1476 cancel_delayed_work_sync(&hdev->service_cache);
1477 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001478 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001479 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001480
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001481 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001482 if (err < 0)
1483 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001484
Johan Hedberg90e70452012-02-23 23:09:40 +02001485 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001486 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001487 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001488 goto unlock;
1489 }
1490
1491 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301492 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001493 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001494
Johan Hedbergb5235a62012-02-21 14:32:24 +02001495unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001496 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001497 return err;
1498}
1499
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001500static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001501 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001502{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001503 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001504 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001505 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001506
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001507 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508
Johan Hedberg86742e12011-11-07 23:13:38 +02001509 expected_len = sizeof(*cp) + key_count *
1510 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001511 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001512 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001513 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001514 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001515 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001516 }
1517
Johan Hedberg4ae14302013-01-20 14:27:13 +02001518 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1519 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1520 MGMT_STATUS_INVALID_PARAMS);
1521
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001522 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001523 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001524
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001525 for (i = 0; i < key_count; i++) {
1526 struct mgmt_link_key_info *key = &cp->keys[i];
1527
1528 if (key->addr.type != BDADDR_BREDR)
1529 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1530 MGMT_STATUS_INVALID_PARAMS);
1531 }
1532
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001533 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001534
1535 hci_link_keys_clear(hdev);
1536
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001537 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001538
1539 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001540 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001541 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001542 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001543
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001544 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001545 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001546
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001547 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001548 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001549 }
1550
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001551 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001552
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001553 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001554
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001555 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001556}
1557
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001558static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001559 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001560{
1561 struct mgmt_ev_device_unpaired ev;
1562
1563 bacpy(&ev.addr.bdaddr, bdaddr);
1564 ev.addr.type = addr_type;
1565
1566 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001567 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001568}
1569
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001570static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001571 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001572{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001573 struct mgmt_cp_unpair_device *cp = data;
1574 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001575 struct hci_cp_disconnect dc;
1576 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001577 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001578 int err;
1579
Johan Hedberga8a1d192011-11-10 15:54:38 +02001580 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001581 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1582 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001583
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001584 if (!bdaddr_type_is_valid(cp->addr.type))
1585 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1586 MGMT_STATUS_INVALID_PARAMS,
1587 &rp, sizeof(rp));
1588
Johan Hedberg118da702013-01-20 14:27:20 +02001589 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1590 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1591 MGMT_STATUS_INVALID_PARAMS,
1592 &rp, sizeof(rp));
1593
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001594 hci_dev_lock(hdev);
1595
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001596 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001597 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001598 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001599 goto unlock;
1600 }
1601
Andre Guedes591f47f2012-04-24 21:02:49 -03001602 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001603 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1604 else
1605 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001606
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001607 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001608 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001609 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001610 goto unlock;
1611 }
1612
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001613 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001614 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001615 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001616 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001617 else
1618 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001619 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001620 } else {
1621 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001622 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001623
Johan Hedberga8a1d192011-11-10 15:54:38 +02001624 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001625 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001626 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001627 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001628 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001629 }
1630
Johan Hedberg124f6e32012-02-09 13:50:12 +02001631 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001632 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001633 if (!cmd) {
1634 err = -ENOMEM;
1635 goto unlock;
1636 }
1637
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001638 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001639 dc.reason = 0x13; /* Remote User Terminated Connection */
1640 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1641 if (err < 0)
1642 mgmt_pending_remove(cmd);
1643
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001644unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001645 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001646 return err;
1647}
1648
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001649static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001650 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001651{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001652 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001653 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001654 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001655 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001656 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001657 int err;
1658
1659 BT_DBG("");
1660
Johan Hedberg06a63b12013-01-20 14:27:21 +02001661 memset(&rp, 0, sizeof(rp));
1662 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1663 rp.addr.type = cp->addr.type;
1664
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001665 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001666 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1667 MGMT_STATUS_INVALID_PARAMS,
1668 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001669
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001670 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001671
1672 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001673 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1674 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001675 goto failed;
1676 }
1677
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001678 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001679 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1680 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001681 goto failed;
1682 }
1683
Andre Guedes591f47f2012-04-24 21:02:49 -03001684 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001685 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1686 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001687 else
1688 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001689
Vishal Agarwalf9607272012-06-13 05:32:43 +05301690 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001691 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1692 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001693 goto failed;
1694 }
1695
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001696 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001697 if (!cmd) {
1698 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001699 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001700 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001701
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001702 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001703 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001704
1705 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1706 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001707 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001708
1709failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001710 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001711 return err;
1712}
1713
Andre Guedes57c14772012-04-24 21:02:50 -03001714static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001715{
1716 switch (link_type) {
1717 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001718 switch (addr_type) {
1719 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001720 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001721
Johan Hedberg48264f02011-11-09 13:58:58 +02001722 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001723 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001724 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001725 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001726
Johan Hedberg4c659c32011-11-07 23:13:39 +02001727 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001728 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001729 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001730 }
1731}
1732
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001733static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1734 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001735{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001736 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001737 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001738 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001739 int err;
1740 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001741
1742 BT_DBG("");
1743
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001744 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001745
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001746 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001747 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001748 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001749 goto unlock;
1750 }
1751
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001752 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001753 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1754 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001755 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001756 }
1757
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001758 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001759 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001760 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001761 err = -ENOMEM;
1762 goto unlock;
1763 }
1764
Johan Hedberg2784eb42011-01-21 13:56:35 +02001765 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001766 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001767 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1768 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001769 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001770 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001771 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001772 continue;
1773 i++;
1774 }
1775
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001776 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001777
Johan Hedberg4c659c32011-11-07 23:13:39 +02001778 /* Recalculate length in case of filtered SCO connections, etc */
1779 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001781 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001782 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001783
Johan Hedberga38528f2011-01-22 06:46:43 +02001784 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001785
1786unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001787 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001788 return err;
1789}
1790
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001791static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001792 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001793{
1794 struct pending_cmd *cmd;
1795 int err;
1796
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001797 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001798 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001799 if (!cmd)
1800 return -ENOMEM;
1801
Johan Hedbergd8457692012-02-17 14:24:57 +02001802 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001803 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001804 if (err < 0)
1805 mgmt_pending_remove(cmd);
1806
1807 return err;
1808}
1809
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001810static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001811 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001812{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001813 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001814 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001815 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001816 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001817 int err;
1818
1819 BT_DBG("");
1820
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001821 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001822
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001823 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001824 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001825 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001826 goto failed;
1827 }
1828
Johan Hedbergd8457692012-02-17 14:24:57 +02001829 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001830 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001831 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001832 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001833 goto failed;
1834 }
1835
1836 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001837 struct mgmt_cp_pin_code_neg_reply ncp;
1838
1839 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001840
1841 BT_ERR("PIN code is not 16 bytes long");
1842
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001843 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001844 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001845 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001846 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001847
1848 goto failed;
1849 }
1850
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001851 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001852 if (!cmd) {
1853 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001854 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001855 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001856
Johan Hedbergd8457692012-02-17 14:24:57 +02001857 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001858 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001859 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001860
1861 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1862 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001863 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001864
1865failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001866 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001867 return err;
1868}
1869
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001870static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1871 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001872{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001873 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001874
1875 BT_DBG("");
1876
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001877 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001878
1879 hdev->io_capability = cp->io_capability;
1880
1881 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001882 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001883
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001884 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001885
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001886 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1887 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001888}
1889
Gustavo Padovan6039aa72012-05-23 04:04:18 -03001890static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891{
1892 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001893 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001895 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001896 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1897 continue;
1898
Johan Hedberge9a416b2011-02-19 12:05:56 -03001899 if (cmd->user_data != conn)
1900 continue;
1901
1902 return cmd;
1903 }
1904
1905 return NULL;
1906}
1907
1908static void pairing_complete(struct pending_cmd *cmd, u8 status)
1909{
1910 struct mgmt_rp_pair_device rp;
1911 struct hci_conn *conn = cmd->user_data;
1912
Johan Hedbergba4e5642011-11-11 00:07:34 +02001913 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001914 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001915
Johan Hedbergaee9b212012-02-18 15:07:59 +02001916 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001917 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001918
1919 /* So we don't get further callbacks for this connection */
1920 conn->connect_cfm_cb = NULL;
1921 conn->security_cfm_cb = NULL;
1922 conn->disconn_cfm_cb = NULL;
1923
1924 hci_conn_put(conn);
1925
Johan Hedberga664b5b2011-02-19 12:06:02 -03001926 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001927}
1928
1929static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1930{
1931 struct pending_cmd *cmd;
1932
1933 BT_DBG("status %u", status);
1934
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001935 cmd = find_pairing(conn);
1936 if (!cmd)
1937 BT_DBG("Unable to find a pending command");
1938 else
Johan Hedberge2113262012-02-18 15:20:03 +02001939 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940}
1941
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301942static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1943{
1944 struct pending_cmd *cmd;
1945
1946 BT_DBG("status %u", status);
1947
1948 if (!status)
1949 return;
1950
1951 cmd = find_pairing(conn);
1952 if (!cmd)
1953 BT_DBG("Unable to find a pending command");
1954 else
1955 pairing_complete(cmd, mgmt_status(status));
1956}
1957
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001958static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001959 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001960{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001961 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001962 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001963 struct pending_cmd *cmd;
1964 u8 sec_level, auth_type;
1965 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001966 int err;
1967
1968 BT_DBG("");
1969
Szymon Jancf950a30e2013-01-18 12:48:07 +01001970 memset(&rp, 0, sizeof(rp));
1971 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1972 rp.addr.type = cp->addr.type;
1973
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001974 if (!bdaddr_type_is_valid(cp->addr.type))
1975 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
1976 MGMT_STATUS_INVALID_PARAMS,
1977 &rp, sizeof(rp));
1978
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001979 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001980
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001981 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01001982 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
1983 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001984 goto unlock;
1985 }
1986
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001987 sec_level = BT_SECURITY_MEDIUM;
1988 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001989 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001990 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001991 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001992
Andre Guedes591f47f2012-04-24 21:02:49 -03001993 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001994 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1995 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001996 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001997 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1998 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001999
Ville Tervo30e76272011-02-22 16:10:53 -03002000 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002001 int status;
2002
2003 if (PTR_ERR(conn) == -EBUSY)
2004 status = MGMT_STATUS_BUSY;
2005 else
2006 status = MGMT_STATUS_CONNECT_FAILED;
2007
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002008 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002009 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002011 goto unlock;
2012 }
2013
2014 if (conn->connect_cfm_cb) {
2015 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002016 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002017 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002018 goto unlock;
2019 }
2020
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002021 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002022 if (!cmd) {
2023 err = -ENOMEM;
2024 hci_conn_put(conn);
2025 goto unlock;
2026 }
2027
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002028 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002029 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002030 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302031 else
2032 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002033
Johan Hedberge9a416b2011-02-19 12:05:56 -03002034 conn->security_cfm_cb = pairing_complete_cb;
2035 conn->disconn_cfm_cb = pairing_complete_cb;
2036 conn->io_capability = cp->io_cap;
2037 cmd->user_data = conn;
2038
2039 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002040 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002041 pairing_complete(cmd, 0);
2042
2043 err = 0;
2044
2045unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002046 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002047 return err;
2048}
2049
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002050static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2051 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002052{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002053 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002054 struct pending_cmd *cmd;
2055 struct hci_conn *conn;
2056 int err;
2057
2058 BT_DBG("");
2059
Johan Hedberg28424702012-02-02 04:02:29 +02002060 hci_dev_lock(hdev);
2061
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002062 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002063 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002064 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002065 goto unlock;
2066 }
2067
Johan Hedberg28424702012-02-02 04:02:29 +02002068 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2069 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002070 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002071 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002072 goto unlock;
2073 }
2074
2075 conn = cmd->user_data;
2076
2077 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002078 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002080 goto unlock;
2081 }
2082
2083 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002085 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002086 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002087unlock:
2088 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002089 return err;
2090}
2091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2094 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002095{
Johan Hedberga5c29682011-02-19 12:05:57 -03002096 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002097 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002098 int err;
2099
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002100 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002101
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002102 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002103 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002104 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002105 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002106 }
2107
Andre Guedes591f47f2012-04-24 21:02:49 -03002108 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002109 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2110 else
Brian Gix47c15e22011-11-16 13:53:14 -08002111 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002112
Johan Hedberg272d90d2012-02-09 15:26:12 +02002113 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002116 goto done;
2117 }
2118
Andre Guedes591f47f2012-04-24 21:02:49 -03002119 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002120 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002121 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002122
Brian Gix5fe57d92011-12-21 16:12:13 -08002123 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002124 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002125 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002126 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002127 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002128 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002129
Brian Gix47c15e22011-11-16 13:53:14 -08002130 goto done;
2131 }
2132
Brian Gix0df4c182011-11-16 13:53:13 -08002133 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002134 if (!cmd) {
2135 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002136 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002137 }
2138
Brian Gix0df4c182011-11-16 13:53:13 -08002139 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002140 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2141 struct hci_cp_user_passkey_reply cp;
2142
2143 bacpy(&cp.bdaddr, bdaddr);
2144 cp.passkey = passkey;
2145 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2146 } else
2147 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2148
Johan Hedberga664b5b2011-02-19 12:06:02 -03002149 if (err < 0)
2150 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002151
Brian Gix0df4c182011-11-16 13:53:13 -08002152done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002153 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002154 return err;
2155}
2156
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302157static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2158 void *data, u16 len)
2159{
2160 struct mgmt_cp_pin_code_neg_reply *cp = data;
2161
2162 BT_DBG("");
2163
2164 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2165 MGMT_OP_PIN_CODE_NEG_REPLY,
2166 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2167}
2168
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002169static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2170 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002171{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002172 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002173
2174 BT_DBG("");
2175
2176 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002180 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002181 MGMT_OP_USER_CONFIRM_REPLY,
2182 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002183}
2184
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002185static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002186 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002187{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002188 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002189
2190 BT_DBG("");
2191
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002192 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002193 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2194 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002195}
2196
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002197static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2198 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002199{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002200 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002201
2202 BT_DBG("");
2203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002204 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002205 MGMT_OP_USER_PASSKEY_REPLY,
2206 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002207}
2208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002209static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002210 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002211{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002212 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002213
2214 BT_DBG("");
2215
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002216 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002217 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2218 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002219}
2220
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002221static int update_name(struct hci_dev *hdev, const char *name)
2222{
2223 struct hci_cp_write_local_name cp;
2224
2225 memcpy(cp.name, name, sizeof(cp.name));
2226
2227 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2228}
2229
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002230static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002232{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002233 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002234 struct pending_cmd *cmd;
2235 int err;
2236
2237 BT_DBG("");
2238
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002239 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002240
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002241 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002242
Johan Hedbergb5235a62012-02-21 14:32:24 +02002243 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002244 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002245
2246 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002247 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002248 if (err < 0)
2249 goto failed;
2250
2251 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002252 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002253
Johan Hedbergb5235a62012-02-21 14:32:24 +02002254 goto failed;
2255 }
2256
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002257 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002258 if (!cmd) {
2259 err = -ENOMEM;
2260 goto failed;
2261 }
2262
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002263 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002264 if (err < 0)
2265 mgmt_pending_remove(cmd);
2266
2267failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002268 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002269 return err;
2270}
2271
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002272static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002273 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002274{
Szymon Jancc35938b2011-03-22 13:12:21 +01002275 struct pending_cmd *cmd;
2276 int err;
2277
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002278 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002279
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002280 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002281
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002282 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002283 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002284 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002285 goto unlock;
2286 }
2287
Andre Guedes9a1a1992012-07-24 15:03:48 -03002288 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002289 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002290 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002291 goto unlock;
2292 }
2293
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002294 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002295 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002296 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002297 goto unlock;
2298 }
2299
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002300 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002301 if (!cmd) {
2302 err = -ENOMEM;
2303 goto unlock;
2304 }
2305
2306 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2307 if (err < 0)
2308 mgmt_pending_remove(cmd);
2309
2310unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002311 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002312 return err;
2313}
2314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002317{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002318 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002319 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002320 int err;
2321
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002323
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002324 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002325
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002326 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002327 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002328 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002329 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002330 else
Szymon Janca6785be2012-12-13 15:11:21 +01002331 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002332
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002333 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002334 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002335
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002336 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002337 return err;
2338}
2339
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002340static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002341 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002342{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002343 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002344 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002345 int err;
2346
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002347 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002348
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002349 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002350
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002351 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002352 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002353 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002354 else
Szymon Janca6785be2012-12-13 15:11:21 +01002355 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002356
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002357 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002358 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002359
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002360 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002361 return err;
2362}
2363
Andre Guedes5e0452c2012-02-17 20:39:38 -03002364int mgmt_interleaved_discovery(struct hci_dev *hdev)
2365{
2366 int err;
2367
2368 BT_DBG("%s", hdev->name);
2369
2370 hci_dev_lock(hdev);
2371
2372 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2373 if (err < 0)
2374 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2375
2376 hci_dev_unlock(hdev);
2377
2378 return err;
2379}
2380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002381static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002382 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002383{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002384 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002385 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002386 int err;
2387
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002388 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002389
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002390 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002391
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002392 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002393 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002394 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002395 goto failed;
2396 }
2397
Andre Guedes642be6c2012-03-21 00:03:37 -03002398 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2399 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2400 MGMT_STATUS_BUSY);
2401 goto failed;
2402 }
2403
Johan Hedbergff9ef572012-01-04 14:23:45 +02002404 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002405 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002406 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002407 goto failed;
2408 }
2409
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002410 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002411 if (!cmd) {
2412 err = -ENOMEM;
2413 goto failed;
2414 }
2415
Andre Guedes4aab14e2012-02-17 20:39:36 -03002416 hdev->discovery.type = cp->type;
2417
2418 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002419 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002420 if (!lmp_bredr_capable(hdev)) {
2421 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2422 MGMT_STATUS_NOT_SUPPORTED);
2423 mgmt_pending_remove(cmd);
2424 goto failed;
2425 }
2426
2427 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002428 break;
2429
2430 case DISCOV_TYPE_LE:
Johan Hedberg04106752013-01-10 14:54:09 +02002431 if (!lmp_host_le_capable(hdev)) {
2432 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2433 MGMT_STATUS_NOT_SUPPORTED);
2434 mgmt_pending_remove(cmd);
2435 goto failed;
2436 }
2437
2438 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2439 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002440 break;
2441
Andre Guedes5e0452c2012-02-17 20:39:38 -03002442 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg04106752013-01-10 14:54:09 +02002443 if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) {
2444 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2445 MGMT_STATUS_NOT_SUPPORTED);
2446 mgmt_pending_remove(cmd);
2447 goto failed;
2448 }
2449
2450 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN,
2451 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002452 break;
2453
Andre Guedesf39799f2012-02-17 20:39:35 -03002454 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002455 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2456 MGMT_STATUS_INVALID_PARAMS);
2457 mgmt_pending_remove(cmd);
2458 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002459 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002460
Johan Hedberg14a53662011-04-27 10:29:56 -04002461 if (err < 0)
2462 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002463 else
2464 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002465
2466failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002467 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002468 return err;
2469}
2470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002471static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002472 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002473{
Johan Hedbergd9306502012-02-20 23:25:18 +02002474 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002475 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002476 struct hci_cp_remote_name_req_cancel cp;
2477 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002478 int err;
2479
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002480 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002481
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002482 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002483
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002484 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002485 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002486 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2487 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002488 goto unlock;
2489 }
2490
2491 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002492 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002493 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2494 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002495 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002496 }
2497
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002498 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002499 if (!cmd) {
2500 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002501 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002502 }
2503
Andre Guedese0d9727e2012-03-20 15:15:36 -03002504 switch (hdev->discovery.state) {
2505 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002506 if (test_bit(HCI_INQUIRY, &hdev->flags))
2507 err = hci_cancel_inquiry(hdev);
2508 else
2509 err = hci_cancel_le_scan(hdev);
2510
Andre Guedese0d9727e2012-03-20 15:15:36 -03002511 break;
2512
2513 case DISCOVERY_RESOLVING:
2514 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002515 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002516 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002517 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002518 err = cmd_complete(sk, hdev->id,
2519 MGMT_OP_STOP_DISCOVERY, 0,
2520 &mgmt_cp->type,
2521 sizeof(mgmt_cp->type));
2522 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2523 goto unlock;
2524 }
2525
2526 bacpy(&cp.bdaddr, &e->data.bdaddr);
2527 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2528 sizeof(cp), &cp);
2529
2530 break;
2531
2532 default:
2533 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2534 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002535 }
2536
Johan Hedberg14a53662011-04-27 10:29:56 -04002537 if (err < 0)
2538 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002539 else
2540 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002541
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002542unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002543 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002544 return err;
2545}
2546
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002547static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002548 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002549{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002550 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002551 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002552 int err;
2553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002554 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002555
Johan Hedberg561aafb2012-01-04 13:31:59 +02002556 hci_dev_lock(hdev);
2557
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002558 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002559 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002560 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002561 goto failed;
2562 }
2563
Johan Hedberga198e7b2012-02-17 14:27:06 +02002564 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002565 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002566 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002567 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002568 goto failed;
2569 }
2570
2571 if (cp->name_known) {
2572 e->name_state = NAME_KNOWN;
2573 list_del(&e->list);
2574 } else {
2575 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002576 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002577 }
2578
Johan Hedberge3846622013-01-09 15:29:33 +02002579 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
2580 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02002581
2582failed:
2583 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002584 return err;
2585}
2586
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002587static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002589{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002590 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002591 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002592 int err;
2593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002594 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002595
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002596 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002597 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
2598 MGMT_STATUS_INVALID_PARAMS,
2599 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002600
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002601 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002602
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002603 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002604 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002605 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002606 else
Szymon Janca6785be2012-12-13 15:11:21 +01002607 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002608
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002609 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002610 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002611
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002612 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002613
2614 return err;
2615}
2616
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002617static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002618 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002619{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002620 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002621 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002622 int err;
2623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002624 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002625
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002626 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002627 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
2628 MGMT_STATUS_INVALID_PARAMS,
2629 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002630
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002631 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002632
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002633 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002634 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002635 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002636 else
Szymon Janca6785be2012-12-13 15:11:21 +01002637 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002638
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002639 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002640 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002641
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002642 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002643
2644 return err;
2645}
2646
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002647static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2648 u16 len)
2649{
2650 struct mgmt_cp_set_device_id *cp = data;
2651 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002652 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002653
2654 BT_DBG("%s", hdev->name);
2655
Szymon Jancc72d4b82012-03-16 16:02:57 +01002656 source = __le16_to_cpu(cp->source);
2657
2658 if (source > 0x0002)
2659 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2660 MGMT_STATUS_INVALID_PARAMS);
2661
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002662 hci_dev_lock(hdev);
2663
Szymon Jancc72d4b82012-03-16 16:02:57 +01002664 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002665 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2666 hdev->devid_product = __le16_to_cpu(cp->product);
2667 hdev->devid_version = __le16_to_cpu(cp->version);
2668
2669 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2670
2671 update_eir(hdev);
2672
2673 hci_dev_unlock(hdev);
2674
2675 return err;
2676}
2677
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002678static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002679 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002680{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002681 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002682 struct hci_cp_write_page_scan_activity acp;
2683 u8 type;
2684 int err;
2685
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002686 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002687
Johan Hedberg33c525c2012-10-24 21:11:58 +03002688 if (!lmp_bredr_capable(hdev))
2689 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2690 MGMT_STATUS_NOT_SUPPORTED);
2691
Johan Hedberga7e80f22013-01-09 16:05:19 +02002692 if (cp->val != 0x00 && cp->val != 0x01)
2693 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2694 MGMT_STATUS_INVALID_PARAMS);
2695
Johan Hedberg5400c042012-02-21 16:40:33 +02002696 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002697 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002698 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002699
2700 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002701 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002702 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002703
2704 hci_dev_lock(hdev);
2705
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002706 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002707 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002708
Johan Hedberg83ce9a062012-06-28 13:44:30 +03002709 /* 160 msec page scan interval */
2710 acp.interval = __constant_cpu_to_le16(0x0100);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002711 } else {
2712 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002713
2714 /* default 1.28 sec page scan */
2715 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002716 }
2717
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002718 /* default 11.25 msec page scan window */
2719 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002720
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002721 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2722 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002723 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002724 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002725 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002726 goto done;
2727 }
2728
2729 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2730 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002731 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002732 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002733 goto done;
2734 }
2735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002736 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002737 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002738done:
2739 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002740 return err;
2741}
2742
Johan Hedberg3f706b72013-01-20 14:27:16 +02002743static bool ltk_is_valid(struct mgmt_ltk_info *key)
2744{
Johan Hedberg44b20d32013-01-20 14:27:17 +02002745 if (key->authenticated != 0x00 && key->authenticated != 0x01)
2746 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02002747 if (key->master != 0x00 && key->master != 0x01)
2748 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002749 if (!bdaddr_type_is_le(key->addr.type))
2750 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02002751 return true;
2752}
2753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002754static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002755 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002756{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002757 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2758 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002759 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002760
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002761 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002762
2763 expected_len = sizeof(*cp) + key_count *
2764 sizeof(struct mgmt_ltk_info);
2765 if (expected_len != len) {
2766 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002767 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002768 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02002769 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002770 }
2771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002772 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002773
Johan Hedberg54ad6d82013-01-20 14:27:15 +02002774 for (i = 0; i < key_count; i++) {
2775 struct mgmt_ltk_info *key = &cp->keys[i];
2776
Johan Hedberg3f706b72013-01-20 14:27:16 +02002777 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02002778 return cmd_status(sk, hdev->id,
2779 MGMT_OP_LOAD_LONG_TERM_KEYS,
2780 MGMT_STATUS_INVALID_PARAMS);
2781 }
2782
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002783 hci_dev_lock(hdev);
2784
2785 hci_smp_ltks_clear(hdev);
2786
2787 for (i = 0; i < key_count; i++) {
2788 struct mgmt_ltk_info *key = &cp->keys[i];
2789 u8 type;
2790
2791 if (key->master)
2792 type = HCI_SMP_LTK;
2793 else
2794 type = HCI_SMP_LTK_SLAVE;
2795
Hemant Gupta4596fde2012-04-16 14:57:40 +05302796 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002797 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002798 type, 0, key->authenticated, key->val,
2799 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002800 }
2801
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002802 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
2803 NULL, 0);
2804
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002805 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002806
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002807 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002808}
2809
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002810static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002811 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2812 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002813 bool var_len;
2814 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002815} mgmt_handlers[] = {
2816 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002817 { read_version, false, MGMT_READ_VERSION_SIZE },
2818 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2819 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2820 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2821 { set_powered, false, MGMT_SETTING_SIZE },
2822 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2823 { set_connectable, false, MGMT_SETTING_SIZE },
2824 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2825 { set_pairable, false, MGMT_SETTING_SIZE },
2826 { set_link_security, false, MGMT_SETTING_SIZE },
2827 { set_ssp, false, MGMT_SETTING_SIZE },
2828 { set_hs, false, MGMT_SETTING_SIZE },
2829 { set_le, false, MGMT_SETTING_SIZE },
2830 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2831 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2832 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2833 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2834 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2835 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2836 { disconnect, false, MGMT_DISCONNECT_SIZE },
2837 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2838 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2839 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2840 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2841 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2842 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2843 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2844 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2845 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2846 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2847 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2848 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2849 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2850 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2851 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2852 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2853 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2854 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2855 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002856 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002857};
2858
2859
Johan Hedberg03811012010-12-08 00:21:06 +02002860int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002862 void *buf;
2863 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002864 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002865 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002866 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002867 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002868 int err;
2869
2870 BT_DBG("got %zu bytes", msglen);
2871
2872 if (msglen < sizeof(*hdr))
2873 return -EINVAL;
2874
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002875 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002876 if (!buf)
2877 return -ENOMEM;
2878
2879 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2880 err = -EFAULT;
2881 goto done;
2882 }
2883
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002884 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002885 opcode = __le16_to_cpu(hdr->opcode);
2886 index = __le16_to_cpu(hdr->index);
2887 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002888
2889 if (len != msglen - sizeof(*hdr)) {
2890 err = -EINVAL;
2891 goto done;
2892 }
2893
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002894 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002895 hdev = hci_dev_get(index);
2896 if (!hdev) {
2897 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002898 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002899 goto done;
2900 }
2901 }
2902
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002903 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002904 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002905 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002906 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002907 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002908 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002909 }
2910
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002911 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002912 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002913 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002914 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002915 goto done;
2916 }
2917
Johan Hedbergbe22b542012-03-01 22:24:41 +02002918 handler = &mgmt_handlers[opcode];
2919
2920 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002921 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002922 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002923 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002924 goto done;
2925 }
2926
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002927 if (hdev)
2928 mgmt_init_hdev(sk, hdev);
2929
2930 cp = buf + sizeof(*hdr);
2931
Johan Hedbergbe22b542012-03-01 22:24:41 +02002932 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002933 if (err < 0)
2934 goto done;
2935
Johan Hedberg03811012010-12-08 00:21:06 +02002936 err = msglen;
2937
2938done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002939 if (hdev)
2940 hci_dev_put(hdev);
2941
Johan Hedberg03811012010-12-08 00:21:06 +02002942 kfree(buf);
2943 return err;
2944}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002945
Johan Hedbergb24752f2011-11-03 14:40:33 +02002946static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2947{
2948 u8 *status = data;
2949
2950 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2951 mgmt_pending_remove(cmd);
2952}
2953
Johan Hedberg744cf192011-11-08 20:40:14 +02002954int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002955{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002956 if (!mgmt_valid_hdev(hdev))
2957 return -ENOTSUPP;
2958
Johan Hedberg744cf192011-11-08 20:40:14 +02002959 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002960}
2961
Johan Hedberg744cf192011-11-08 20:40:14 +02002962int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002963{
Johan Hedberg5f159032012-03-02 03:13:19 +02002964 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002965
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002966 if (!mgmt_valid_hdev(hdev))
2967 return -ENOTSUPP;
2968
Johan Hedberg744cf192011-11-08 20:40:14 +02002969 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002970
Johan Hedberg744cf192011-11-08 20:40:14 +02002971 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002972}
2973
Johan Hedberg73f22f62010-12-29 16:00:25 +02002974struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002975 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002976 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002977 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002978};
2979
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002980static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002981{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002982 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002983
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002984 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002985
2986 list_del(&cmd->list);
2987
2988 if (match->sk == NULL) {
2989 match->sk = cmd->sk;
2990 sock_hold(match->sk);
2991 }
2992
2993 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002994}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002995
Johan Hedberg7f0ae642012-10-24 21:11:57 +03002996static int set_bredr_scan(struct hci_dev *hdev)
2997{
2998 u8 scan = 0;
2999
3000 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3001 scan |= SCAN_PAGE;
3002 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3003 scan |= SCAN_INQUIRY;
3004
3005 if (!scan)
3006 return 0;
3007
3008 return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3009}
3010
Johan Hedberg744cf192011-11-08 20:40:14 +02003011int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003012{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003013 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003014 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003015
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003016 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3017 return 0;
3018
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003019 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02003020
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003021 if (powered) {
Johan Hedberg6b4b73e2012-10-25 00:09:52 +03003022 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3023 !lmp_host_ssp_capable(hdev)) {
Andrzej Kaczmarek3d1cbdd2012-08-29 10:02:08 +02003024 u8 ssp = 1;
3025
3026 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
3027 }
3028
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003029 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
3030 struct hci_cp_write_le_host_supported cp;
3031
3032 cp.le = 1;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02003033 cp.simul = lmp_le_br_capable(hdev);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003034
Johan Hedberg430a61b2012-10-25 00:09:53 +03003035 /* Check first if we already have the right
3036 * host state (host features set)
3037 */
Gustavo Padovanffa88e02012-11-23 16:50:51 -02003038 if (cp.le != lmp_host_le_capable(hdev) ||
3039 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg430a61b2012-10-25 00:09:53 +03003040 hci_send_cmd(hdev,
3041 HCI_OP_WRITE_LE_HOST_SUPPORTED,
3042 sizeof(cp), &cp);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003043 }
3044
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003045 if (lmp_bredr_capable(hdev)) {
3046 set_bredr_scan(hdev);
3047 update_class(hdev);
3048 update_name(hdev, hdev->dev_name);
3049 update_eir(hdev);
3050 }
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003051 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02003052 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedbergfe038882013-01-16 16:15:34 +02003053 u8 zero_cod[] = { 0, 0, 0 };
3054
Johan Hedberg744cf192011-11-08 20:40:14 +02003055 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergfe038882013-01-16 16:15:34 +02003056
3057 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3058 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3059 zero_cod, sizeof(zero_cod), NULL);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003060 }
3061
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003062 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003063
3064 if (match.sk)
3065 sock_put(match.sk);
3066
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003067 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003068}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003069
Johan Hedberg744cf192011-11-08 20:40:14 +02003070int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003071{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003072 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003073 bool changed = false;
3074 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003075
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003076 if (discoverable) {
3077 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3078 changed = true;
3079 } else {
3080 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3081 changed = true;
3082 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003083
Johan Hedberged9b5f22012-02-21 20:47:06 +02003084 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003085 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003086
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003087 if (changed)
3088 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003089
Johan Hedberg73f22f62010-12-29 16:00:25 +02003090 if (match.sk)
3091 sock_put(match.sk);
3092
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003093 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003094}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003095
Johan Hedberg744cf192011-11-08 20:40:14 +02003096int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003097{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003098 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003099 bool changed = false;
3100 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003101
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003102 if (connectable) {
3103 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3104 changed = true;
3105 } else {
3106 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3107 changed = true;
3108 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003109
Johan Hedberged9b5f22012-02-21 20:47:06 +02003110 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003111 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003112
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003113 if (changed)
3114 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003115
3116 if (match.sk)
3117 sock_put(match.sk);
3118
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003119 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003120}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003121
Johan Hedberg744cf192011-11-08 20:40:14 +02003122int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003123{
Johan Hedbergca69b792011-11-11 18:10:00 +02003124 u8 mgmt_err = mgmt_status(status);
3125
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003126 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003127 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003128 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003129
3130 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003131 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003133
3134 return 0;
3135}
3136
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003137int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3138 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003139{
Johan Hedberg86742e12011-11-07 23:13:38 +02003140 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003141
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003142 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003143
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003144 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003145 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003146 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003147 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003148 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003149 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003150
Johan Hedberg744cf192011-11-08 20:40:14 +02003151 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003152}
Johan Hedbergf7520542011-01-20 12:34:39 +02003153
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003154int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3155{
3156 struct mgmt_ev_new_long_term_key ev;
3157
3158 memset(&ev, 0, sizeof(ev));
3159
3160 ev.store_hint = persistent;
3161 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003162 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003163 ev.key.authenticated = key->authenticated;
3164 ev.key.enc_size = key->enc_size;
3165 ev.key.ediv = key->ediv;
3166
3167 if (key->type == HCI_SMP_LTK)
3168 ev.key.master = 1;
3169
3170 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3171 memcpy(ev.key.val, key->val, sizeof(key->val));
3172
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003173 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3174 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003175}
3176
Johan Hedbergafc747a2012-01-15 18:11:07 +02003177int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003178 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3179 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003180{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003181 char buf[512];
3182 struct mgmt_ev_device_connected *ev = (void *) buf;
3183 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003184
Johan Hedbergb644ba32012-01-17 21:48:47 +02003185 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003186 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003187
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003188 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003189
Johan Hedbergb644ba32012-01-17 21:48:47 +02003190 if (name_len > 0)
3191 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003192 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003193
3194 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003195 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003196 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003197
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003198 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003199
3200 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003201 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003202}
3203
Johan Hedberg8962ee72011-01-20 12:40:27 +02003204static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3205{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003206 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003207 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003208 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003209
Johan Hedberg88c3df12012-02-09 14:27:38 +02003210 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3211 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003212
Johan Hedbergaee9b212012-02-18 15:07:59 +02003213 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003214 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003215
3216 *sk = cmd->sk;
3217 sock_hold(*sk);
3218
Johan Hedberga664b5b2011-02-19 12:06:02 -03003219 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003220}
3221
Johan Hedberg124f6e32012-02-09 13:50:12 +02003222static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003223{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003224 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003225 struct mgmt_cp_unpair_device *cp = cmd->param;
3226 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003227
3228 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003229 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3230 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003231
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003232 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3233
Johan Hedbergaee9b212012-02-18 15:07:59 +02003234 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003235
3236 mgmt_pending_remove(cmd);
3237}
3238
Johan Hedbergafc747a2012-01-15 18:11:07 +02003239int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003240 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003241{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003242 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003243 struct sock *sk = NULL;
3244 int err;
3245
Johan Hedberg744cf192011-11-08 20:40:14 +02003246 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003247
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003248 bacpy(&ev.addr.bdaddr, bdaddr);
3249 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3250 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003251
Johan Hedbergafc747a2012-01-15 18:11:07 +02003252 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003253 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003254
3255 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003256 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003257
Johan Hedberg124f6e32012-02-09 13:50:12 +02003258 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003259 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003260
Johan Hedberg8962ee72011-01-20 12:40:27 +02003261 return err;
3262}
3263
Johan Hedberg88c3df12012-02-09 14:27:38 +02003264int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003265 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003266{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003267 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003268 struct pending_cmd *cmd;
3269 int err;
3270
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003271 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3272 hdev);
3273
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003274 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003275 if (!cmd)
3276 return -ENOENT;
3277
Johan Hedberg88c3df12012-02-09 14:27:38 +02003278 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003279 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003280
Johan Hedberg88c3df12012-02-09 14:27:38 +02003281 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003282 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003283
Johan Hedberga664b5b2011-02-19 12:06:02 -03003284 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003285
3286 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003287}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003288
Johan Hedberg48264f02011-11-09 13:58:58 +02003289int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003290 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003291{
3292 struct mgmt_ev_connect_failed ev;
3293
Johan Hedberg4c659c32011-11-07 23:13:39 +02003294 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003295 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003296 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003297
Johan Hedberg744cf192011-11-08 20:40:14 +02003298 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003299}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003300
Johan Hedberg744cf192011-11-08 20:40:14 +02003301int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003302{
3303 struct mgmt_ev_pin_code_request ev;
3304
Johan Hedbergd8457692012-02-17 14:24:57 +02003305 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003306 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003307 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003308
Johan Hedberg744cf192011-11-08 20:40:14 +02003309 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003310 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003311}
3312
Johan Hedberg744cf192011-11-08 20:40:14 +02003313int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003314 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003315{
3316 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003317 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003318 int err;
3319
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003320 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003321 if (!cmd)
3322 return -ENOENT;
3323
Johan Hedbergd8457692012-02-17 14:24:57 +02003324 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003325 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003326
Johan Hedbergaee9b212012-02-18 15:07:59 +02003327 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003328 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003329
Johan Hedberga664b5b2011-02-19 12:06:02 -03003330 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003331
3332 return err;
3333}
3334
Johan Hedberg744cf192011-11-08 20:40:14 +02003335int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003336 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003337{
3338 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003339 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003340 int err;
3341
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003342 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003343 if (!cmd)
3344 return -ENOENT;
3345
Johan Hedbergd8457692012-02-17 14:24:57 +02003346 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003347 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003348
Johan Hedbergaee9b212012-02-18 15:07:59 +02003349 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003350 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003351
Johan Hedberga664b5b2011-02-19 12:06:02 -03003352 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003353
3354 return err;
3355}
Johan Hedberga5c29682011-02-19 12:05:57 -03003356
Johan Hedberg744cf192011-11-08 20:40:14 +02003357int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003358 u8 link_type, u8 addr_type, __le32 value,
3359 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003360{
3361 struct mgmt_ev_user_confirm_request ev;
3362
Johan Hedberg744cf192011-11-08 20:40:14 +02003363 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003364
Johan Hedberg272d90d2012-02-09 15:26:12 +02003365 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003366 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003367 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003368 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003369
Johan Hedberg744cf192011-11-08 20:40:14 +02003370 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003371 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003372}
3373
Johan Hedberg272d90d2012-02-09 15:26:12 +02003374int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003375 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003376{
3377 struct mgmt_ev_user_passkey_request ev;
3378
3379 BT_DBG("%s", hdev->name);
3380
Johan Hedberg272d90d2012-02-09 15:26:12 +02003381 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003382 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003383
3384 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003385 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003386}
3387
Brian Gix0df4c182011-11-16 13:53:13 -08003388static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003389 u8 link_type, u8 addr_type, u8 status,
3390 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003391{
3392 struct pending_cmd *cmd;
3393 struct mgmt_rp_user_confirm_reply rp;
3394 int err;
3395
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003396 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003397 if (!cmd)
3398 return -ENOENT;
3399
Johan Hedberg272d90d2012-02-09 15:26:12 +02003400 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003401 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003402 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003403 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003404
Johan Hedberga664b5b2011-02-19 12:06:02 -03003405 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003406
3407 return err;
3408}
3409
Johan Hedberg744cf192011-11-08 20:40:14 +02003410int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003411 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003412{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003413 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003414 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003415}
3416
Johan Hedberg272d90d2012-02-09 15:26:12 +02003417int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003418 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003419{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003420 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003421 status,
3422 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003423}
Johan Hedberg2a611692011-02-19 12:06:00 -03003424
Brian Gix604086b2011-11-23 08:28:33 -08003425int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003426 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003427{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003428 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003429 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003430}
3431
Johan Hedberg272d90d2012-02-09 15:26:12 +02003432int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003433 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003434{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003435 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003436 status,
3437 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003438}
3439
Johan Hedberg92a25252012-09-06 18:39:26 +03003440int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3441 u8 link_type, u8 addr_type, u32 passkey,
3442 u8 entered)
3443{
3444 struct mgmt_ev_passkey_notify ev;
3445
3446 BT_DBG("%s", hdev->name);
3447
3448 bacpy(&ev.addr.bdaddr, bdaddr);
3449 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3450 ev.passkey = __cpu_to_le32(passkey);
3451 ev.entered = entered;
3452
3453 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3454}
3455
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003456int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003457 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003458{
3459 struct mgmt_ev_auth_failed ev;
3460
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003461 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003462 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003463 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003464
Johan Hedberg744cf192011-11-08 20:40:14 +02003465 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003466}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003467
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003468int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3469{
3470 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003471 bool changed = false;
3472 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003473
3474 if (status) {
3475 u8 mgmt_err = mgmt_status(status);
3476 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003477 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003478 return 0;
3479 }
3480
Johan Hedberg47990ea2012-02-22 11:58:37 +02003481 if (test_bit(HCI_AUTH, &hdev->flags)) {
3482 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3483 changed = true;
3484 } else {
3485 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3486 changed = true;
3487 }
3488
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003489 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003490 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003491
Johan Hedberg47990ea2012-02-22 11:58:37 +02003492 if (changed)
3493 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003494
3495 if (match.sk)
3496 sock_put(match.sk);
3497
3498 return err;
3499}
3500
Johan Hedbergcacaf522012-02-21 00:52:42 +02003501static int clear_eir(struct hci_dev *hdev)
3502{
3503 struct hci_cp_write_eir cp;
3504
Johan Hedberg976eb202012-10-24 21:12:01 +03003505 if (!lmp_ext_inq_capable(hdev))
Johan Hedbergcacaf522012-02-21 00:52:42 +02003506 return 0;
3507
Johan Hedbergc80da272012-02-22 15:38:48 +02003508 memset(hdev->eir, 0, sizeof(hdev->eir));
3509
Johan Hedbergcacaf522012-02-21 00:52:42 +02003510 memset(&cp, 0, sizeof(cp));
3511
3512 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3513}
3514
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003515int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003516{
3517 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003518 bool changed = false;
3519 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003520
3521 if (status) {
3522 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003523
3524 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003525 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003526 err = new_settings(hdev, NULL);
3527
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003528 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3529 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003530
3531 return err;
3532 }
3533
3534 if (enable) {
3535 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3536 changed = true;
3537 } else {
3538 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3539 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003540 }
3541
3542 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3543
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003544 if (changed)
3545 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003546
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003547 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003548 sock_put(match.sk);
3549
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003550 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3551 update_eir(hdev);
3552 else
3553 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003554
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003555 return err;
3556}
3557
Johan Hedberg90e70452012-02-23 23:09:40 +02003558static void class_rsp(struct pending_cmd *cmd, void *data)
3559{
3560 struct cmd_lookup *match = data;
3561
3562 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003563 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003564
3565 list_del(&cmd->list);
3566
3567 if (match->sk == NULL) {
3568 match->sk = cmd->sk;
3569 sock_hold(match->sk);
3570 }
3571
3572 mgmt_pending_free(cmd);
3573}
3574
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003575int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003576 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003577{
Johan Hedberg90e70452012-02-23 23:09:40 +02003578 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3579 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003580
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003581 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3582
Johan Hedberg90e70452012-02-23 23:09:40 +02003583 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3584 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3585 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3586
3587 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003588 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3589 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003590
3591 if (match.sk)
3592 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003593
3594 return err;
3595}
3596
Johan Hedberg744cf192011-11-08 20:40:14 +02003597int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003598{
3599 struct pending_cmd *cmd;
3600 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003601 bool changed = false;
3602 int err = 0;
3603
3604 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3605 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3606 changed = true;
3607 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003608
3609 memset(&ev, 0, sizeof(ev));
3610 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003611 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003612
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003613 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003614 if (!cmd)
3615 goto send_event;
3616
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003617 /* Always assume that either the short or the complete name has
3618 * changed if there was a pending mgmt command */
3619 changed = true;
3620
Johan Hedbergb312b1612011-03-16 14:29:37 +02003621 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003622 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003623 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003624 goto failed;
3625 }
3626
Johan Hedbergaee9b212012-02-18 15:07:59 +02003627 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003628 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003629 if (err < 0)
3630 goto failed;
3631
3632send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003633 if (changed)
3634 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003635 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003636
Johan Hedberg1225a6b2012-10-25 00:09:54 +03003637 /* EIR is taken care of separately when powering on the
3638 * adapter so only update them here if this is a name change
3639 * unrelated to power on.
3640 */
3641 if (!test_bit(HCI_INIT, &hdev->flags))
3642 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003643
3644failed:
3645 if (cmd)
3646 mgmt_pending_remove(cmd);
3647 return err;
3648}
Szymon Jancc35938b2011-03-22 13:12:21 +01003649
Johan Hedberg744cf192011-11-08 20:40:14 +02003650int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003651 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003652{
3653 struct pending_cmd *cmd;
3654 int err;
3655
Johan Hedberg744cf192011-11-08 20:40:14 +02003656 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003657
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003658 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003659 if (!cmd)
3660 return -ENOENT;
3661
3662 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003663 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3664 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003665 } else {
3666 struct mgmt_rp_read_local_oob_data rp;
3667
3668 memcpy(rp.hash, hash, sizeof(rp.hash));
3669 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3670
Johan Hedberg744cf192011-11-08 20:40:14 +02003671 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003672 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3673 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003674 }
3675
3676 mgmt_pending_remove(cmd);
3677
3678 return err;
3679}
Johan Hedberge17acd42011-03-30 23:57:16 +03003680
Johan Hedberg06199cf2012-02-22 16:37:11 +02003681int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3682{
3683 struct cmd_lookup match = { NULL, hdev };
3684 bool changed = false;
3685 int err = 0;
3686
3687 if (status) {
3688 u8 mgmt_err = mgmt_status(status);
3689
3690 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003691 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003692 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003693
Szymon Jancd97dcb62012-03-16 16:02:56 +01003694 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3695 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003696
3697 return err;
3698 }
3699
3700 if (enable) {
3701 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3702 changed = true;
3703 } else {
3704 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3705 changed = true;
3706 }
3707
3708 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3709
3710 if (changed)
3711 err = new_settings(hdev, match.sk);
3712
3713 if (match.sk)
3714 sock_put(match.sk);
3715
3716 return err;
3717}
3718
Johan Hedberg48264f02011-11-09 13:58:58 +02003719int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003720 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3721 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003722{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003723 char buf[512];
3724 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003725 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003726
Johan Hedberg1dc06092012-01-15 21:01:23 +02003727 /* Leave 5 bytes for a potential CoD field */
3728 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003729 return -EINVAL;
3730
Johan Hedberg1dc06092012-01-15 21:01:23 +02003731 memset(buf, 0, sizeof(buf));
3732
Johan Hedberge319d2e2012-01-15 19:51:59 +02003733 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003734 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003735 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003736 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303737 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003738 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303739 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003740
Johan Hedberg1dc06092012-01-15 21:01:23 +02003741 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003742 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003743
Johan Hedberg1dc06092012-01-15 21:01:23 +02003744 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3745 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003746 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003747
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003748 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003749 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003750
Johan Hedberge319d2e2012-01-15 19:51:59 +02003751 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003752}
Johan Hedberga88a9652011-03-30 13:18:12 +03003753
Johan Hedbergb644ba32012-01-17 21:48:47 +02003754int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003755 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003756{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003757 struct mgmt_ev_device_found *ev;
3758 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3759 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003760
Johan Hedbergb644ba32012-01-17 21:48:47 +02003761 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003762
Johan Hedbergb644ba32012-01-17 21:48:47 +02003763 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003764
Johan Hedbergb644ba32012-01-17 21:48:47 +02003765 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003766 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003767 ev->rssi = rssi;
3768
3769 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003770 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003771
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003772 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003773
Johan Hedberg053c7e02012-02-04 00:06:00 +02003774 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003775 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003776}
Johan Hedberg314b2382011-04-27 10:29:57 -04003777
Andre Guedes7a135102011-11-09 17:14:25 -03003778int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003779{
3780 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003781 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003782 int err;
3783
Andre Guedes203159d2012-02-13 15:41:01 -03003784 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3785
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003786 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003787 if (!cmd)
3788 return -ENOENT;
3789
Johan Hedbergf808e162012-02-19 12:52:07 +02003790 type = hdev->discovery.type;
3791
3792 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003793 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003794 mgmt_pending_remove(cmd);
3795
3796 return err;
3797}
3798
Andre Guedese6d465c2011-11-09 17:14:26 -03003799int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3800{
3801 struct pending_cmd *cmd;
3802 int err;
3803
3804 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3805 if (!cmd)
3806 return -ENOENT;
3807
Johan Hedbergd9306502012-02-20 23:25:18 +02003808 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003809 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003810 mgmt_pending_remove(cmd);
3811
3812 return err;
3813}
Johan Hedberg314b2382011-04-27 10:29:57 -04003814
Johan Hedberg744cf192011-11-08 20:40:14 +02003815int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003816{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003817 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003818 struct pending_cmd *cmd;
3819
Andre Guedes343fb142011-11-22 17:14:19 -03003820 BT_DBG("%s discovering %u", hdev->name, discovering);
3821
Johan Hedberg164a6e72011-11-01 17:06:44 +02003822 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003823 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003824 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003825 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003826
3827 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003828 u8 type = hdev->discovery.type;
3829
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003830 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3831 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003832 mgmt_pending_remove(cmd);
3833 }
3834
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003835 memset(&ev, 0, sizeof(ev));
3836 ev.type = hdev->discovery.type;
3837 ev.discovering = discovering;
3838
3839 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003840}
Antti Julku5e762442011-08-25 16:48:02 +03003841
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003842int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003843{
3844 struct pending_cmd *cmd;
3845 struct mgmt_ev_device_blocked ev;
3846
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003847 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003848
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003849 bacpy(&ev.addr.bdaddr, bdaddr);
3850 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003851
Johan Hedberg744cf192011-11-08 20:40:14 +02003852 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003853 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003854}
3855
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003856int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003857{
3858 struct pending_cmd *cmd;
3859 struct mgmt_ev_device_unblocked ev;
3860
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003861 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003862
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003863 bacpy(&ev.addr.bdaddr, bdaddr);
3864 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003865
Johan Hedberg744cf192011-11-08 20:40:14 +02003866 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003867 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003868}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003869
3870module_param(enable_hs, bool, 0644);
3871MODULE_PARM_DESC(enable_hs, "Enable High Speed support");