blob: aa2ea0a8142cc0d6c7378ced06be1257b2f846d7 [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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200218
Andre Guedes790eff42012-06-07 19:05:46 -0300219 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220 if (!skb)
221 return -ENOMEM;
222
223 hdr = (void *) skb_put(skb, sizeof(*hdr));
224
225 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100226 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200235 kfree_skb(skb);
236
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300237 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200238}
239
Johan Hedbergaee9b2182012-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
Johan Hedberg02d98122010-12-13 21:07:04 +0200256 hdr->opcode = 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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedberga38528f2011-01-22 06:46:43 +0200329 int i, 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
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200350 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200351
352 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200353 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200354 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200355 continue;
356
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300357 if (!mgmt_valid_hdev(d))
358 continue;
359
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200360 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200361 BT_DBG("Added hci%u", d->id);
362 }
363
364 read_unlock(&hci_dev_list_lock);
365
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200366 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300367 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200368
Johan Hedberga38528f2011-01-22 06:46:43 +0200369 kfree(rp);
370
371 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372}
373
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200375{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 settings |= MGMT_SETTING_POWERED;
379 settings |= MGMT_SETTING_CONNECTABLE;
380 settings |= MGMT_SETTING_FAST_CONNECTABLE;
381 settings |= MGMT_SETTING_DISCOVERABLE;
382 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200383
Andre Guedes9a1a1992012-07-24 15:03:48 -0300384 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200385 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200386
Andre Guedesed3fa312012-07-24 15:03:46 -0300387 if (lmp_bredr_capable(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 settings |= MGMT_SETTING_BREDR;
389 settings |= MGMT_SETTING_LINK_SECURITY;
390 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200391
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100392 if (enable_hs)
393 settings |= MGMT_SETTING_HS;
394
Andre Guedesc383ddc2012-07-24 15:03:47 -0300395 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200396 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200397
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200398 return settings;
399}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200400
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401static u32 get_current_settings(struct hci_dev *hdev)
402{
403 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200404
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200405 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100406 settings |= MGMT_SETTING_POWERED;
407
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200408 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_CONNECTABLE;
410
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200411 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_DISCOVERABLE;
413
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200414 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_PAIRABLE;
416
Andre Guedesed3fa312012-07-24 15:03:46 -0300417 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_BREDR;
419
Johan Hedberg06199cf2012-02-22 16:37:11 +0200420 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200422
Johan Hedberg47990ea2012-02-22 11:58:37 +0200423 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200424 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200425
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200426 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200427 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200428
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200429 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
430 settings |= MGMT_SETTING_HS;
431
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200432 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200433}
434
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300435#define PNP_INFO_SVCLASS_ID 0x1200
436
437static u8 bluetooth_base_uuid[] = {
438 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
439 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440};
441
442static u16 get_uuid16(u8 *uuid128)
443{
444 u32 val;
445 int i;
446
447 for (i = 0; i < 12; i++) {
448 if (bluetooth_base_uuid[i] != uuid128[i])
449 return 0;
450 }
451
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200452 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300453 if (val > 0xffff)
454 return 0;
455
456 return (u16) val;
457}
458
459static void create_eir(struct hci_dev *hdev, u8 *data)
460{
461 u8 *ptr = data;
462 u16 eir_len = 0;
463 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
464 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200465 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300466 size_t name_len;
467
468 name_len = strlen(hdev->dev_name);
469
470 if (name_len > 0) {
471 /* EIR Data type */
472 if (name_len > 48) {
473 name_len = 48;
474 ptr[1] = EIR_NAME_SHORT;
475 } else
476 ptr[1] = EIR_NAME_COMPLETE;
477
478 /* EIR Data length */
479 ptr[0] = name_len + 1;
480
481 memcpy(ptr + 2, hdev->dev_name, name_len);
482
483 eir_len += (name_len + 2);
484 ptr += (name_len + 2);
485 }
486
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700487 if (hdev->inq_tx_power) {
488 ptr[0] = 2;
489 ptr[1] = EIR_TX_POWER;
490 ptr[2] = (u8) hdev->inq_tx_power;
491
492 eir_len += 3;
493 ptr += 3;
494 }
495
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700496 if (hdev->devid_source > 0) {
497 ptr[0] = 9;
498 ptr[1] = EIR_DEVICE_ID;
499
500 put_unaligned_le16(hdev->devid_source, ptr + 2);
501 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
502 put_unaligned_le16(hdev->devid_product, ptr + 6);
503 put_unaligned_le16(hdev->devid_version, ptr + 8);
504
505 eir_len += 10;
506 ptr += 10;
507 }
508
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300509 memset(uuid16_list, 0, sizeof(uuid16_list));
510
511 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200512 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300513 u16 uuid16;
514
515 uuid16 = get_uuid16(uuid->uuid);
516 if (uuid16 == 0)
517 return;
518
519 if (uuid16 < 0x1100)
520 continue;
521
522 if (uuid16 == PNP_INFO_SVCLASS_ID)
523 continue;
524
525 /* Stop if not enough space to put next UUID */
526 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
527 truncated = 1;
528 break;
529 }
530
531 /* Check for duplicates */
532 for (i = 0; uuid16_list[i] != 0; i++)
533 if (uuid16_list[i] == uuid16)
534 break;
535
536 if (uuid16_list[i] == 0) {
537 uuid16_list[i] = uuid16;
538 eir_len += sizeof(u16);
539 }
540 }
541
542 if (uuid16_list[0] != 0) {
543 u8 *length = ptr;
544
545 /* EIR Data type */
546 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
547
548 ptr += 2;
549 eir_len += 2;
550
551 for (i = 0; uuid16_list[i] != 0; i++) {
552 *ptr++ = (uuid16_list[i] & 0x00ff);
553 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
554 }
555
556 /* EIR Data length */
557 *length = (i * sizeof(u16)) + 1;
558 }
559}
560
561static int update_eir(struct hci_dev *hdev)
562{
563 struct hci_cp_write_eir cp;
564
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200565 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200566 return 0;
567
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300568 if (!(hdev->features[6] & LMP_EXT_INQ))
569 return 0;
570
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200571 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300572 return 0;
573
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200574 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300575 return 0;
576
577 memset(&cp, 0, sizeof(cp));
578
579 create_eir(hdev, cp.data);
580
581 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
582 return 0;
583
584 memcpy(hdev->eir, cp.data, sizeof(cp.data));
585
586 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
587}
588
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200589static u8 get_service_classes(struct hci_dev *hdev)
590{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300591 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200592 u8 val = 0;
593
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300594 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200596
597 return val;
598}
599
600static int update_class(struct hci_dev *hdev)
601{
602 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200603 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200604
605 BT_DBG("%s", hdev->name);
606
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200607 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200608 return 0;
609
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200610 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200611 return 0;
612
613 cod[0] = hdev->minor_class;
614 cod[1] = hdev->major_class;
615 cod[2] = get_service_classes(hdev);
616
617 if (memcmp(cod, hdev->dev_class, 3) == 0)
618 return 0;
619
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200620 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
621 if (err == 0)
622 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
623
624 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200625}
626
Johan Hedberg7d785252011-12-15 00:47:39 +0200627static void service_cache_off(struct work_struct *work)
628{
629 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300630 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200631
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200632 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200633 return;
634
635 hci_dev_lock(hdev);
636
637 update_eir(hdev);
638 update_class(hdev);
639
640 hci_dev_unlock(hdev);
641}
642
Johan Hedberg6a919082012-02-28 06:17:26 +0200643static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200644{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200645 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200646 return;
647
Johan Hedberg4f87da82012-03-02 19:55:56 +0200648 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200649
Johan Hedberg4f87da82012-03-02 19:55:56 +0200650 /* Non-mgmt controlled devices get this bit set
651 * implicitly so that pairing works for them, however
652 * for mgmt we require user-space to explicitly enable
653 * it
654 */
655 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200656}
657
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200658static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300659 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200660{
661 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200662
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200663 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300665 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200666
Johan Hedberg03811012010-12-08 00:21:06 +0200667 memset(&rp, 0, sizeof(rp));
668
Johan Hedberg03811012010-12-08 00:21:06 +0200669 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200670
671 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200672 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200673
674 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
675 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
676
677 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200678
679 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200680 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200681
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300682 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200683
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200684 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300685 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200686}
687
688static void mgmt_pending_free(struct pending_cmd *cmd)
689{
690 sock_put(cmd->sk);
691 kfree(cmd->param);
692 kfree(cmd);
693}
694
695static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300696 struct hci_dev *hdev, void *data,
697 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200698{
699 struct pending_cmd *cmd;
700
Andre Guedes12b94562012-06-07 19:05:45 -0300701 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200702 if (!cmd)
703 return NULL;
704
705 cmd->opcode = opcode;
706 cmd->index = hdev->id;
707
Andre Guedes12b94562012-06-07 19:05:45 -0300708 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200709 if (!cmd->param) {
710 kfree(cmd);
711 return NULL;
712 }
713
714 if (data)
715 memcpy(cmd->param, data, len);
716
717 cmd->sk = sk;
718 sock_hold(sk);
719
720 list_add(&cmd->list, &hdev->mgmt_pending);
721
722 return cmd;
723}
724
725static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300726 void (*cb)(struct pending_cmd *cmd,
727 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300728 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200729{
730 struct list_head *p, *n;
731
732 list_for_each_safe(p, n, &hdev->mgmt_pending) {
733 struct pending_cmd *cmd;
734
735 cmd = list_entry(p, struct pending_cmd, list);
736
737 if (opcode > 0 && cmd->opcode != opcode)
738 continue;
739
740 cb(cmd, data);
741 }
742}
743
744static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
745{
746 struct pending_cmd *cmd;
747
748 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
749 if (cmd->opcode == opcode)
750 return cmd;
751 }
752
753 return NULL;
754}
755
756static void mgmt_pending_remove(struct pending_cmd *cmd)
757{
758 list_del(&cmd->list);
759 mgmt_pending_free(cmd);
760}
761
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200762static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200763{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200764 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200765
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200766 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300767 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200768}
769
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200770static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300771 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200772{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300773 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200774 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200775 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200776
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200777 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200778
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300779 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200780
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100781 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
782 cancel_delayed_work(&hdev->power_off);
783
784 if (cp->val) {
785 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
786 mgmt_powered(hdev, 1);
787 goto failed;
788 }
789 }
790
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200791 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200792 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200793 goto failed;
794 }
795
796 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200797 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300798 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200799 goto failed;
800 }
801
802 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
803 if (!cmd) {
804 err = -ENOMEM;
805 goto failed;
806 }
807
808 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200809 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200810 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200811 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200812
813 err = 0;
814
815failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300816 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200817 return err;
818}
819
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300820static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
821 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200822{
823 struct sk_buff *skb;
824 struct mgmt_hdr *hdr;
825
Andre Guedes790eff42012-06-07 19:05:46 -0300826 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200827 if (!skb)
828 return -ENOMEM;
829
830 hdr = (void *) skb_put(skb, sizeof(*hdr));
831 hdr->opcode = cpu_to_le16(event);
832 if (hdev)
833 hdr->index = cpu_to_le16(hdev->id);
834 else
835 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
836 hdr->len = cpu_to_le16(data_len);
837
838 if (data)
839 memcpy(skb_put(skb, data_len), data, data_len);
840
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100841 /* Time stamp */
842 __net_timestamp(skb);
843
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200844 hci_send_to_control(skb, skip_sk);
845 kfree_skb(skb);
846
847 return 0;
848}
849
850static int new_settings(struct hci_dev *hdev, struct sock *skip)
851{
852 __le32 ev;
853
854 ev = cpu_to_le32(get_current_settings(hdev));
855
856 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
857}
858
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200859static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300860 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300862 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200863 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200864 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200865 u8 scan;
866 int err;
867
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200868 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200869
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700870 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100871 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200872 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300873 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200874
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300875 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200876
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200877 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200878 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300879 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200880 goto failed;
881 }
882
883 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300884 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200885 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300886 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200887 goto failed;
888 }
889
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200890 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200891 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300892 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200893 goto failed;
894 }
895
896 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200897 bool changed = false;
898
899 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
900 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
901 changed = true;
902 }
903
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200904 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200905 if (err < 0)
906 goto failed;
907
908 if (changed)
909 err = new_settings(hdev, sk);
910
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200911 goto failed;
912 }
913
914 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100915 if (hdev->discov_timeout > 0) {
916 cancel_delayed_work(&hdev->discov_off);
917 hdev->discov_timeout = 0;
918 }
919
920 if (cp->val && timeout > 0) {
921 hdev->discov_timeout = timeout;
922 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
923 msecs_to_jiffies(hdev->discov_timeout * 1000));
924 }
925
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200926 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200927 goto failed;
928 }
929
930 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
931 if (!cmd) {
932 err = -ENOMEM;
933 goto failed;
934 }
935
936 scan = SCAN_PAGE;
937
938 if (cp->val)
939 scan |= SCAN_INQUIRY;
940 else
941 cancel_delayed_work(&hdev->discov_off);
942
943 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
944 if (err < 0)
945 mgmt_pending_remove(cmd);
946
Johan Hedberg03811012010-12-08 00:21:06 +0200947 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200948 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200949
950failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300951 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200952 return err;
953}
954
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200955static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300956 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200957{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300958 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200959 struct pending_cmd *cmd;
960 u8 scan;
961 int err;
962
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200963 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200964
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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001035 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036
1037 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001038 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001039 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001040 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001041
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001042 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043 if (err < 0)
1044 goto failed;
1045
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001046 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047
1048failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001049 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001050 return err;
1051}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001052
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001053static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1054 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001055{
1056 struct mgmt_mode *cp = data;
1057 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001058 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001059 int err;
1060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001061 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001062
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001063 hci_dev_lock(hdev);
1064
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001065 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001066 bool changed = false;
1067
1068 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001069 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001070 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1071 changed = true;
1072 }
1073
1074 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1075 if (err < 0)
1076 goto failed;
1077
1078 if (changed)
1079 err = new_settings(hdev, sk);
1080
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001081 goto failed;
1082 }
1083
1084 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001085 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001086 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001087 goto failed;
1088 }
1089
1090 val = !!cp->val;
1091
1092 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1093 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1094 goto failed;
1095 }
1096
1097 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1098 if (!cmd) {
1099 err = -ENOMEM;
1100 goto failed;
1101 }
1102
1103 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1104 if (err < 0) {
1105 mgmt_pending_remove(cmd);
1106 goto failed;
1107 }
1108
1109failed:
1110 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001111 return err;
1112}
1113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001114static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001115{
1116 struct mgmt_mode *cp = data;
1117 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001118 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001119 int err;
1120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001121 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001122
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001123 hci_dev_lock(hdev);
1124
Andre Guedes9a1a1992012-07-24 15:03:48 -03001125 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001126 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001127 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001128 goto failed;
1129 }
1130
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001131 val = !!cp->val;
1132
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001133 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001134 bool changed = false;
1135
1136 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1137 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1138 changed = true;
1139 }
1140
1141 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1142 if (err < 0)
1143 goto failed;
1144
1145 if (changed)
1146 err = new_settings(hdev, sk);
1147
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001148 goto failed;
1149 }
1150
1151 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001152 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1153 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001154 goto failed;
1155 }
1156
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001157 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1158 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1159 goto failed;
1160 }
1161
1162 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1163 if (!cmd) {
1164 err = -ENOMEM;
1165 goto failed;
1166 }
1167
1168 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1169 if (err < 0) {
1170 mgmt_pending_remove(cmd);
1171 goto failed;
1172 }
1173
1174failed:
1175 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001176 return err;
1177}
1178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001179static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001180{
1181 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001183 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001184
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001185 if (!enable_hs)
1186 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001187 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001188
1189 if (cp->val)
1190 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1191 else
1192 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001194 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001195}
1196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001197static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001198{
1199 struct mgmt_mode *cp = data;
1200 struct hci_cp_write_le_host_supported hci_cp;
1201 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001203 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001205 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001206
Johan Hedberg1de028c2012-02-29 19:55:35 -08001207 hci_dev_lock(hdev);
1208
Andre Guedesc383ddc2012-07-24 15:03:47 -03001209 if (!lmp_le_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001210 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001211 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001212 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001213 }
1214
1215 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001216 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001217
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001218 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001219 bool changed = false;
1220
1221 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1222 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1223 changed = true;
1224 }
1225
1226 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1227 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001228 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001229
1230 if (changed)
1231 err = new_settings(hdev, sk);
1232
Johan Hedberg1de028c2012-02-29 19:55:35 -08001233 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001234 }
1235
1236 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001237 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001238 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001239 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001240 }
1241
1242 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1243 if (!cmd) {
1244 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001245 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001246 }
1247
1248 memset(&hci_cp, 0, sizeof(hci_cp));
1249
1250 if (val) {
1251 hci_cp.le = val;
1252 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1253 }
1254
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001255 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1256 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301257 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001258 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001259
Johan Hedberg1de028c2012-02-29 19:55:35 -08001260unlock:
1261 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001262 return err;
1263}
1264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001265static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001266{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001267 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001268 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001269 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001270 int err;
1271
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001272 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001273
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001274 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001275
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001276 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001278 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001279 goto failed;
1280 }
1281
Andre Guedes92c4c202012-06-07 19:05:44 -03001282 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001283 if (!uuid) {
1284 err = -ENOMEM;
1285 goto failed;
1286 }
1287
1288 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001289 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001290
1291 list_add(&uuid->list, &hdev->uuids);
1292
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001293 err = update_class(hdev);
1294 if (err < 0)
1295 goto failed;
1296
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001297 err = update_eir(hdev);
1298 if (err < 0)
1299 goto failed;
1300
Johan Hedberg90e70452012-02-23 23:09:40 +02001301 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001302 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001303 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001304 goto failed;
1305 }
1306
1307 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301308 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001309 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001310
1311failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001312 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001313 return err;
1314}
1315
Johan Hedberg24b78d02012-02-23 23:24:30 +02001316static bool enable_service_cache(struct hci_dev *hdev)
1317{
1318 if (!hdev_is_powered(hdev))
1319 return false;
1320
1321 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001322 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001323 return true;
1324 }
1325
1326 return false;
1327}
1328
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001329static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001330 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001331{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001332 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001333 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 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 +02001336 int err, found;
1337
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001338 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001339
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001340 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001342 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001343 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001344 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001345 goto unlock;
1346 }
1347
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001348 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1349 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001350
Johan Hedberg24b78d02012-02-23 23:24:30 +02001351 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001352 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001353 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001354 goto unlock;
1355 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001356
Johan Hedberg9246a862012-02-23 21:33:16 +02001357 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001358 }
1359
1360 found = 0;
1361
1362 list_for_each_safe(p, n, &hdev->uuids) {
1363 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1364
1365 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1366 continue;
1367
1368 list_del(&match->list);
1369 found++;
1370 }
1371
1372 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001373 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001374 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001375 goto unlock;
1376 }
1377
Johan Hedberg9246a862012-02-23 21:33:16 +02001378update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001379 err = update_class(hdev);
1380 if (err < 0)
1381 goto unlock;
1382
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001383 err = update_eir(hdev);
1384 if (err < 0)
1385 goto unlock;
1386
Johan Hedberg90e70452012-02-23 23:09:40 +02001387 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001388 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001389 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001390 goto unlock;
1391 }
1392
1393 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301394 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001395 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001396
1397unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001398 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001399 return err;
1400}
1401
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001402static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001403 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001404{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001405 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001406 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001407 int err;
1408
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001409 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001410
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001411 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001412
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001413 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001414 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001415 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001416 goto unlock;
1417 }
1418
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001419 hdev->major_class = cp->major;
1420 hdev->minor_class = cp->minor;
1421
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001422 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001423 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001424 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001425 goto unlock;
1426 }
1427
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001428 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001429 hci_dev_unlock(hdev);
1430 cancel_delayed_work_sync(&hdev->service_cache);
1431 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001432 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001433 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001434
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001435 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001436 if (err < 0)
1437 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001438
Johan Hedberg90e70452012-02-23 23:09:40 +02001439 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001440 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001441 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001442 goto unlock;
1443 }
1444
1445 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301446 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001447 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001448
Johan Hedbergb5235a62012-02-21 14:32:24 +02001449unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001450 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001451 return err;
1452}
1453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001454static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001455 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001456{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001457 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001458 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001459 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001460
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001461 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001462
Johan Hedberg86742e12011-11-07 23:13:38 +02001463 expected_len = sizeof(*cp) + key_count *
1464 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001465 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001466 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001467 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001468 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001469 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001470 }
1471
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001472 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001473 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001474
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001475 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001476
1477 hci_link_keys_clear(hdev);
1478
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001479 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001480
1481 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001482 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001483 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001484 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001485
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001486 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001487 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001488
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001489 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001490 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001491 }
1492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001493 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001494
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001495 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001496
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001497 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001498}
1499
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001500static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001501 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001502{
1503 struct mgmt_ev_device_unpaired ev;
1504
1505 bacpy(&ev.addr.bdaddr, bdaddr);
1506 ev.addr.type = addr_type;
1507
1508 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001509 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001510}
1511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001512static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001513 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001514{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001515 struct mgmt_cp_unpair_device *cp = data;
1516 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001517 struct hci_cp_disconnect dc;
1518 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001519 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001520 int err;
1521
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001522 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523
Johan Hedberga8a1d192011-11-10 15:54:38 +02001524 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001525 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1526 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001527
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001528 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001529 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001530 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001531 goto unlock;
1532 }
1533
Andre Guedes591f47f2012-04-24 21:02:49 -03001534 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001535 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1536 else
1537 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001538
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001539 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001540 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001541 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542 goto unlock;
1543 }
1544
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001545 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001546 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001547 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001548 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001549 else
1550 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001551 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001552 } else {
1553 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001554 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001555
Johan Hedberga8a1d192011-11-10 15:54:38 +02001556 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001557 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001558 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001559 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001560 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001561 }
1562
Johan Hedberg124f6e32012-02-09 13:50:12 +02001563 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001564 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001565 if (!cmd) {
1566 err = -ENOMEM;
1567 goto unlock;
1568 }
1569
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001570 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001571 dc.reason = 0x13; /* Remote User Terminated Connection */
1572 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1573 if (err < 0)
1574 mgmt_pending_remove(cmd);
1575
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001576unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001577 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001578 return err;
1579}
1580
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001581static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001582 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001583{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001584 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001585 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001586 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001587 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001588 int err;
1589
1590 BT_DBG("");
1591
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001592 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001593
1594 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001595 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001596 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001597 goto failed;
1598 }
1599
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001600 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001601 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001602 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001603 goto failed;
1604 }
1605
Andre Guedes591f47f2012-04-24 21:02:49 -03001606 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001607 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1608 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001609 else
1610 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001611
Vishal Agarwalf9607272012-06-13 05:32:43 +05301612 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001613 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001614 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615 goto failed;
1616 }
1617
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001618 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001619 if (!cmd) {
1620 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001621 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001622 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001623
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001624 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001625 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001626
1627 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1628 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001629 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001630
1631failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001632 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001633 return err;
1634}
1635
Andre Guedes57c14772012-04-24 21:02:50 -03001636static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001637{
1638 switch (link_type) {
1639 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001640 switch (addr_type) {
1641 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001642 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001643
Johan Hedberg48264f02011-11-09 13:58:58 +02001644 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001645 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001646 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001647 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001648
Johan Hedberg4c659c32011-11-07 23:13:39 +02001649 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001650 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001651 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001652 }
1653}
1654
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001655static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1656 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001657{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001658 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001659 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001660 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001661 int err;
1662 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001663
1664 BT_DBG("");
1665
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001666 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001668 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001669 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001670 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001671 goto unlock;
1672 }
1673
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001674 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001675 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1676 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001677 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001678 }
1679
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001680 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001681 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001682 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001683 err = -ENOMEM;
1684 goto unlock;
1685 }
1686
Johan Hedberg2784eb42011-01-21 13:56:35 +02001687 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001688 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001689 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1690 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001691 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001692 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001693 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001694 continue;
1695 i++;
1696 }
1697
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001698 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001699
Johan Hedberg4c659c32011-11-07 23:13:39 +02001700 /* Recalculate length in case of filtered SCO connections, etc */
1701 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001702
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001703 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001704 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001705
Johan Hedberga38528f2011-01-22 06:46:43 +02001706 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001707
1708unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001709 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001710 return err;
1711}
1712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001713static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001715{
1716 struct pending_cmd *cmd;
1717 int err;
1718
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001719 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001720 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001721 if (!cmd)
1722 return -ENOMEM;
1723
Johan Hedbergd8457692012-02-17 14:24:57 +02001724 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001725 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001726 if (err < 0)
1727 mgmt_pending_remove(cmd);
1728
1729 return err;
1730}
1731
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001732static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001733 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001734{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001735 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001736 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001738 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001739 int err;
1740
1741 BT_DBG("");
1742
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001743 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001744
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001745 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001746 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001747 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001748 goto failed;
1749 }
1750
Johan Hedbergd8457692012-02-17 14:24:57 +02001751 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001752 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001753 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001754 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001755 goto failed;
1756 }
1757
1758 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001759 struct mgmt_cp_pin_code_neg_reply ncp;
1760
1761 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001762
1763 BT_ERR("PIN code is not 16 bytes long");
1764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001766 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001768 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001769
1770 goto failed;
1771 }
1772
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001773 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001774 if (!cmd) {
1775 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001776 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001777 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778
Johan Hedbergd8457692012-02-17 14:24:57 +02001779 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001781 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001782
1783 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1784 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001785 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001786
1787failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001788 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789 return err;
1790}
1791
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001792static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1793 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001794{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001795 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001796
1797 BT_DBG("");
1798
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001799 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001800
1801 hdev->io_capability = cp->io_capability;
1802
1803 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001804 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001806 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001807
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001808 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1809 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001810}
1811
Gustavo Padovan6039aa732012-05-23 04:04:18 -03001812static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001813{
1814 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001815 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001816
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001817 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001818 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1819 continue;
1820
Johan Hedberge9a416b2011-02-19 12:05:56 -03001821 if (cmd->user_data != conn)
1822 continue;
1823
1824 return cmd;
1825 }
1826
1827 return NULL;
1828}
1829
1830static void pairing_complete(struct pending_cmd *cmd, u8 status)
1831{
1832 struct mgmt_rp_pair_device rp;
1833 struct hci_conn *conn = cmd->user_data;
1834
Johan Hedbergba4e5642011-11-11 00:07:34 +02001835 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001836 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001837
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001838 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001839 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001840
1841 /* So we don't get further callbacks for this connection */
1842 conn->connect_cfm_cb = NULL;
1843 conn->security_cfm_cb = NULL;
1844 conn->disconn_cfm_cb = NULL;
1845
1846 hci_conn_put(conn);
1847
Johan Hedberga664b5b2011-02-19 12:06:02 -03001848 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001849}
1850
1851static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1852{
1853 struct pending_cmd *cmd;
1854
1855 BT_DBG("status %u", status);
1856
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001857 cmd = find_pairing(conn);
1858 if (!cmd)
1859 BT_DBG("Unable to find a pending command");
1860 else
Johan Hedberge2113262012-02-18 15:20:03 +02001861 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001862}
1863
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301864static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1865{
1866 struct pending_cmd *cmd;
1867
1868 BT_DBG("status %u", status);
1869
1870 if (!status)
1871 return;
1872
1873 cmd = find_pairing(conn);
1874 if (!cmd)
1875 BT_DBG("Unable to find a pending command");
1876 else
1877 pairing_complete(cmd, mgmt_status(status));
1878}
1879
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001880static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001881 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001882{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001883 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001884 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001885 struct pending_cmd *cmd;
1886 u8 sec_level, auth_type;
1887 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001888 int err;
1889
1890 BT_DBG("");
1891
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001892 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001893
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001894 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001895 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001896 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001897 goto unlock;
1898 }
1899
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001900 sec_level = BT_SECURITY_MEDIUM;
1901 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001902 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001903 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001904 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001905
Andre Guedes591f47f2012-04-24 21:02:49 -03001906 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001907 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1908 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001909 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001910 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1911 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001912
Johan Hedberg1425acb2011-11-11 00:07:35 +02001913 memset(&rp, 0, sizeof(rp));
1914 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1915 rp.addr.type = cp->addr.type;
1916
Ville Tervo30e76272011-02-22 16:10:53 -03001917 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001918 int status;
1919
1920 if (PTR_ERR(conn) == -EBUSY)
1921 status = MGMT_STATUS_BUSY;
1922 else
1923 status = MGMT_STATUS_CONNECT_FAILED;
1924
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001925 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001926 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001927 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001928 goto unlock;
1929 }
1930
1931 if (conn->connect_cfm_cb) {
1932 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001933 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001934 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001935 goto unlock;
1936 }
1937
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001938 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001939 if (!cmd) {
1940 err = -ENOMEM;
1941 hci_conn_put(conn);
1942 goto unlock;
1943 }
1944
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001945 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001946 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001947 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301948 else
1949 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001950
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 conn->security_cfm_cb = pairing_complete_cb;
1952 conn->disconn_cfm_cb = pairing_complete_cb;
1953 conn->io_capability = cp->io_cap;
1954 cmd->user_data = conn;
1955
1956 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001957 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03001958 pairing_complete(cmd, 0);
1959
1960 err = 0;
1961
1962unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001963 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001964 return err;
1965}
1966
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001967static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1968 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001969{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001970 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001971 struct pending_cmd *cmd;
1972 struct hci_conn *conn;
1973 int err;
1974
1975 BT_DBG("");
1976
Johan Hedberg28424702012-02-02 04:02:29 +02001977 hci_dev_lock(hdev);
1978
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001979 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001980 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001981 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001982 goto unlock;
1983 }
1984
Johan Hedberg28424702012-02-02 04:02:29 +02001985 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1986 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001987 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001988 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001989 goto unlock;
1990 }
1991
1992 conn = cmd->user_data;
1993
1994 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001995 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001996 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001997 goto unlock;
1998 }
1999
2000 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002002 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002003 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002004unlock:
2005 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002006 return err;
2007}
2008
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002009static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2011 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002012{
Johan Hedberga5c29682011-02-19 12:05:57 -03002013 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002014 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002015 int err;
2016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002017 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002018
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002019 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002020 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002021 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002022 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002023 }
2024
Andre Guedes591f47f2012-04-24 21:02:49 -03002025 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002026 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2027 else
Brian Gix47c15e22011-11-16 13:53:14 -08002028 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002029
Johan Hedberg272d90d2012-02-09 15:26:12 +02002030 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002031 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002032 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002033 goto done;
2034 }
2035
Andre Guedes591f47f2012-04-24 21:02:49 -03002036 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002037 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002038 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002039
Brian Gix5fe57d92011-12-21 16:12:13 -08002040 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002041 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002042 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002043 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002045 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002046
Brian Gix47c15e22011-11-16 13:53:14 -08002047 goto done;
2048 }
2049
Brian Gix0df4c182011-11-16 13:53:13 -08002050 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002051 if (!cmd) {
2052 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002053 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002054 }
2055
Brian Gix0df4c182011-11-16 13:53:13 -08002056 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002057 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2058 struct hci_cp_user_passkey_reply cp;
2059
2060 bacpy(&cp.bdaddr, bdaddr);
2061 cp.passkey = passkey;
2062 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2063 } else
2064 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2065
Johan Hedberga664b5b2011-02-19 12:06:02 -03002066 if (err < 0)
2067 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002068
Brian Gix0df4c182011-11-16 13:53:13 -08002069done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002070 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002071 return err;
2072}
2073
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302074static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2075 void *data, u16 len)
2076{
2077 struct mgmt_cp_pin_code_neg_reply *cp = data;
2078
2079 BT_DBG("");
2080
2081 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2082 MGMT_OP_PIN_CODE_NEG_REPLY,
2083 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2084}
2085
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002086static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2087 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002089 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002090
2091 BT_DBG("");
2092
2093 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002094 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002095 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098 MGMT_OP_USER_CONFIRM_REPLY,
2099 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002100}
2101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002102static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002103 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002104{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002105 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002106
2107 BT_DBG("");
2108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002110 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2111 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002112}
2113
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002114static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2115 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002116{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002117 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002118
2119 BT_DBG("");
2120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002121 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002122 MGMT_OP_USER_PASSKEY_REPLY,
2123 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002124}
2125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002126static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002127 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002128{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002129 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002130
2131 BT_DBG("");
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002134 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2135 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002136}
2137
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002138static int update_name(struct hci_dev *hdev, const char *name)
2139{
2140 struct hci_cp_write_local_name cp;
2141
2142 memcpy(cp.name, name, sizeof(cp.name));
2143
2144 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2145}
2146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002147static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002148 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002149{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002150 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002151 struct pending_cmd *cmd;
2152 int err;
2153
2154 BT_DBG("");
2155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002157
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002158 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002159
Johan Hedbergb5235a62012-02-21 14:32:24 +02002160 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002161 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002162
2163 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002164 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002165 if (err < 0)
2166 goto failed;
2167
2168 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002169 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002170
Johan Hedbergb5235a62012-02-21 14:32:24 +02002171 goto failed;
2172 }
2173
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002174 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002175 if (!cmd) {
2176 err = -ENOMEM;
2177 goto failed;
2178 }
2179
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002180 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002181 if (err < 0)
2182 mgmt_pending_remove(cmd);
2183
2184failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002185 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002186 return err;
2187}
2188
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002189static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002191{
Szymon Jancc35938b2011-03-22 13:12:21 +01002192 struct pending_cmd *cmd;
2193 int err;
2194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002195 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002196
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002197 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002198
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002199 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002202 goto unlock;
2203 }
2204
Andre Guedes9a1a1992012-07-24 15:03:48 -03002205 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002206 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002207 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002208 goto unlock;
2209 }
2210
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002211 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002212 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002213 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002214 goto unlock;
2215 }
2216
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002217 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002218 if (!cmd) {
2219 err = -ENOMEM;
2220 goto unlock;
2221 }
2222
2223 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2224 if (err < 0)
2225 mgmt_pending_remove(cmd);
2226
2227unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002228 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002229 return err;
2230}
2231
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002234{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002235 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002236 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002237 int err;
2238
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002239 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002240
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002241 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002242
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002243 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002244 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002245 MGMT_STATUS_NOT_POWERED, &cp->addr,
2246 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002247 goto unlock;
2248 }
2249
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002250 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002251 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002252 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002253 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002254 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002255 status = 0;
2256
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002257 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002258 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002259
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002260unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002261 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002262 return err;
2263}
2264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002266 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002267{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002268 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002269 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002270 int err;
2271
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002272 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002273
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002274 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002275
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002276 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002277 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002278 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2279 MGMT_STATUS_NOT_POWERED, &cp->addr,
2280 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002281 goto unlock;
2282 }
2283
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002284 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002285 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002286 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002287 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002288 status = 0;
2289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002290 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002291 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002292
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002293unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002294 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002295 return err;
2296}
2297
Andre Guedes5e0452c2012-02-17 20:39:38 -03002298int mgmt_interleaved_discovery(struct hci_dev *hdev)
2299{
2300 int err;
2301
2302 BT_DBG("%s", hdev->name);
2303
2304 hci_dev_lock(hdev);
2305
2306 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2307 if (err < 0)
2308 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2309
2310 hci_dev_unlock(hdev);
2311
2312 return err;
2313}
2314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002317{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002318 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002319 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002320 int err;
2321
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002323
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002324 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002325
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002326 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002327 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002328 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002329 goto failed;
2330 }
2331
Andre Guedes642be6c2012-03-21 00:03:37 -03002332 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2333 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2334 MGMT_STATUS_BUSY);
2335 goto failed;
2336 }
2337
Johan Hedbergff9ef572012-01-04 14:23:45 +02002338 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002339 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002341 goto failed;
2342 }
2343
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002344 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002345 if (!cmd) {
2346 err = -ENOMEM;
2347 goto failed;
2348 }
2349
Andre Guedes4aab14e2012-02-17 20:39:36 -03002350 hdev->discovery.type = cp->type;
2351
2352 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002353 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002354 if (lmp_bredr_capable(hdev))
2355 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2356 else
2357 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002358 break;
2359
2360 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002361 if (lmp_host_le_capable(hdev))
2362 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002363 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002364 else
2365 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002366 break;
2367
Andre Guedes5e0452c2012-02-17 20:39:38 -03002368 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002369 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2370 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002371 LE_SCAN_WIN,
2372 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002373 else
2374 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002375 break;
2376
Andre Guedesf39799f2012-02-17 20:39:35 -03002377 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002378 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002379 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002380
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 if (err < 0)
2382 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002383 else
2384 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002385
2386failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002387 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002388 return err;
2389}
2390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002391static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002392 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002393{
Johan Hedbergd9306502012-02-20 23:25:18 +02002394 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002395 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002396 struct hci_cp_remote_name_req_cancel cp;
2397 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002398 int err;
2399
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002400 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002401
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002402 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002403
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002404 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002405 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002406 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2407 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002408 goto unlock;
2409 }
2410
2411 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002412 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002413 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2414 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002415 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002416 }
2417
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002418 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002419 if (!cmd) {
2420 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002421 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002422 }
2423
Andre Guedese0d9727e2012-03-20 15:15:36 -03002424 switch (hdev->discovery.state) {
2425 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002426 if (test_bit(HCI_INQUIRY, &hdev->flags))
2427 err = hci_cancel_inquiry(hdev);
2428 else
2429 err = hci_cancel_le_scan(hdev);
2430
Andre Guedese0d9727e2012-03-20 15:15:36 -03002431 break;
2432
2433 case DISCOVERY_RESOLVING:
2434 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002435 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002436 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002437 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002438 err = cmd_complete(sk, hdev->id,
2439 MGMT_OP_STOP_DISCOVERY, 0,
2440 &mgmt_cp->type,
2441 sizeof(mgmt_cp->type));
2442 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2443 goto unlock;
2444 }
2445
2446 bacpy(&cp.bdaddr, &e->data.bdaddr);
2447 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2448 sizeof(cp), &cp);
2449
2450 break;
2451
2452 default:
2453 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2454 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002455 }
2456
Johan Hedberg14a53662011-04-27 10:29:56 -04002457 if (err < 0)
2458 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002459 else
2460 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002461
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002462unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002464 return err;
2465}
2466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002467static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002468 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002469{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002470 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002471 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002472 int err;
2473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002474 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002475
Johan Hedberg561aafb2012-01-04 13:31:59 +02002476 hci_dev_lock(hdev);
2477
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002478 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002481 goto failed;
2482 }
2483
Johan Hedberga198e7b2012-02-17 14:27:06 +02002484 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002485 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002486 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002487 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002488 goto failed;
2489 }
2490
2491 if (cp->name_known) {
2492 e->name_state = NAME_KNOWN;
2493 list_del(&e->list);
2494 } else {
2495 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002496 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002497 }
2498
2499 err = 0;
2500
2501failed:
2502 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002503 return err;
2504}
2505
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002506static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002507 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002508{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002509 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002510 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002511 int err;
2512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002513 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002514
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002515 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002516
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002517 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002518 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002519 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002520 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002521 status = 0;
2522
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002523 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002524 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002525
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002526 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002527
2528 return err;
2529}
2530
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002531static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002533{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002534 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002535 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002536 int err;
2537
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002538 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002540 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002541
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002542 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002543 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002544 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002545 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002546 status = 0;
2547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002548 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002549 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002550
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002551 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002552
2553 return err;
2554}
2555
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002556static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2557 u16 len)
2558{
2559 struct mgmt_cp_set_device_id *cp = data;
2560 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002561 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002562
2563 BT_DBG("%s", hdev->name);
2564
Szymon Jancc72d4b82012-03-16 16:02:57 +01002565 source = __le16_to_cpu(cp->source);
2566
2567 if (source > 0x0002)
2568 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2569 MGMT_STATUS_INVALID_PARAMS);
2570
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002571 hci_dev_lock(hdev);
2572
Szymon Jancc72d4b82012-03-16 16:02:57 +01002573 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002574 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2575 hdev->devid_product = __le16_to_cpu(cp->product);
2576 hdev->devid_version = __le16_to_cpu(cp->version);
2577
2578 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2579
2580 update_eir(hdev);
2581
2582 hci_dev_unlock(hdev);
2583
2584 return err;
2585}
2586
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002587static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002589{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002590 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002591 struct hci_cp_write_page_scan_activity acp;
2592 u8 type;
2593 int err;
2594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002595 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002596
Johan Hedberg5400c042012-02-21 16:40:33 +02002597 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002598 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002599 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002600
2601 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002602 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002603 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002604
2605 hci_dev_lock(hdev);
2606
Johan Hedbergf7c68692011-12-15 00:47:36 +02002607 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002608 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002609
Johan Hedberg83ce9a062012-06-28 13:44:30 +03002610 /* 160 msec page scan interval */
2611 acp.interval = __constant_cpu_to_le16(0x0100);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002612 } else {
2613 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002614
2615 /* default 1.28 sec page scan */
2616 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002617 }
2618
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002619 /* default 11.25 msec page scan window */
2620 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002621
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002622 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2623 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002624 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002625 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002626 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002627 goto done;
2628 }
2629
2630 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2631 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002632 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002633 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002634 goto done;
2635 }
2636
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002639done:
2640 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002641 return err;
2642}
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002646{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002647 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2648 u16 key_count, expected_len;
2649 int i;
2650
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002651 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002652
2653 expected_len = sizeof(*cp) + key_count *
2654 sizeof(struct mgmt_ltk_info);
2655 if (expected_len != len) {
2656 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002657 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002658 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002659 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002660 }
2661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002663
2664 hci_dev_lock(hdev);
2665
2666 hci_smp_ltks_clear(hdev);
2667
2668 for (i = 0; i < key_count; i++) {
2669 struct mgmt_ltk_info *key = &cp->keys[i];
2670 u8 type;
2671
2672 if (key->master)
2673 type = HCI_SMP_LTK;
2674 else
2675 type = HCI_SMP_LTK_SLAVE;
2676
Hemant Gupta4596fde2012-04-16 14:57:40 +05302677 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002678 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002679 type, 0, key->authenticated, key->val,
2680 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002681 }
2682
2683 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002684
2685 return 0;
2686}
2687
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002688static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002689 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2690 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002691 bool var_len;
2692 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002693} mgmt_handlers[] = {
2694 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002695 { read_version, false, MGMT_READ_VERSION_SIZE },
2696 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2697 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2698 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2699 { set_powered, false, MGMT_SETTING_SIZE },
2700 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2701 { set_connectable, false, MGMT_SETTING_SIZE },
2702 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2703 { set_pairable, false, MGMT_SETTING_SIZE },
2704 { set_link_security, false, MGMT_SETTING_SIZE },
2705 { set_ssp, false, MGMT_SETTING_SIZE },
2706 { set_hs, false, MGMT_SETTING_SIZE },
2707 { set_le, false, MGMT_SETTING_SIZE },
2708 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2709 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2710 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2711 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2712 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2713 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2714 { disconnect, false, MGMT_DISCONNECT_SIZE },
2715 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2716 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2717 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2718 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2719 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2720 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2721 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2722 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2723 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2724 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2725 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2726 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2727 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2728 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2729 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2730 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2731 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2732 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2733 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002734 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002735};
2736
2737
Johan Hedberg03811012010-12-08 00:21:06 +02002738int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2739{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002740 void *buf;
2741 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002742 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002743 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002744 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002745 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002746 int err;
2747
2748 BT_DBG("got %zu bytes", msglen);
2749
2750 if (msglen < sizeof(*hdr))
2751 return -EINVAL;
2752
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002753 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002754 if (!buf)
2755 return -ENOMEM;
2756
2757 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2758 err = -EFAULT;
2759 goto done;
2760 }
2761
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002762 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002763 opcode = __le16_to_cpu(hdr->opcode);
2764 index = __le16_to_cpu(hdr->index);
2765 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002766
2767 if (len != msglen - sizeof(*hdr)) {
2768 err = -EINVAL;
2769 goto done;
2770 }
2771
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002772 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002773 hdev = hci_dev_get(index);
2774 if (!hdev) {
2775 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002776 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002777 goto done;
2778 }
2779 }
2780
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002781 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002782 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002783 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002784 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002785 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002786 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002787 }
2788
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002789 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002790 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002791 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002792 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002793 goto done;
2794 }
2795
Johan Hedbergbe22b542012-03-01 22:24:41 +02002796 handler = &mgmt_handlers[opcode];
2797
2798 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002799 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002800 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002801 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002802 goto done;
2803 }
2804
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002805 if (hdev)
2806 mgmt_init_hdev(sk, hdev);
2807
2808 cp = buf + sizeof(*hdr);
2809
Johan Hedbergbe22b542012-03-01 22:24:41 +02002810 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002811 if (err < 0)
2812 goto done;
2813
Johan Hedberg03811012010-12-08 00:21:06 +02002814 err = msglen;
2815
2816done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002817 if (hdev)
2818 hci_dev_put(hdev);
2819
Johan Hedberg03811012010-12-08 00:21:06 +02002820 kfree(buf);
2821 return err;
2822}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002823
Johan Hedbergb24752f2011-11-03 14:40:33 +02002824static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2825{
2826 u8 *status = data;
2827
2828 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2829 mgmt_pending_remove(cmd);
2830}
2831
Johan Hedberg744cf192011-11-08 20:40:14 +02002832int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002833{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002834 if (!mgmt_valid_hdev(hdev))
2835 return -ENOTSUPP;
2836
Johan Hedberg744cf192011-11-08 20:40:14 +02002837 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002838}
2839
Johan Hedberg744cf192011-11-08 20:40:14 +02002840int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002841{
Johan Hedberg5f159032012-03-02 03:13:19 +02002842 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002843
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002844 if (!mgmt_valid_hdev(hdev))
2845 return -ENOTSUPP;
2846
Johan Hedberg744cf192011-11-08 20:40:14 +02002847 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002848
Johan Hedberg744cf192011-11-08 20:40:14 +02002849 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002850}
2851
Johan Hedberg73f22f62010-12-29 16:00:25 +02002852struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002853 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002854 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002855 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002856};
2857
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002858static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002859{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002860 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002861
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002862 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002863
2864 list_del(&cmd->list);
2865
2866 if (match->sk == NULL) {
2867 match->sk = cmd->sk;
2868 sock_hold(match->sk);
2869 }
2870
2871 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002872}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002873
Johan Hedberg744cf192011-11-08 20:40:14 +02002874int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002875{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002876 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002877 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002878
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002879 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2880 return 0;
2881
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002882 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002883
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002884 if (powered) {
2885 u8 scan = 0;
2886
2887 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2888 scan |= SCAN_PAGE;
2889 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2890 scan |= SCAN_INQUIRY;
2891
2892 if (scan)
2893 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002894
Andrzej Kaczmarek3d1cbdd2012-08-29 10:02:08 +02002895 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
2896 u8 ssp = 1;
2897
2898 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
2899 }
2900
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02002901 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
2902 struct hci_cp_write_le_host_supported cp;
2903
2904 cp.le = 1;
2905 cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
2906
2907 hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
2908 sizeof(cp), &cp);
2909 }
2910
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002911 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002912 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002913 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002914 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002915 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002916 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002917 }
2918
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002919 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002920
2921 if (match.sk)
2922 sock_put(match.sk);
2923
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002924 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002925}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002926
Johan Hedberg744cf192011-11-08 20:40:14 +02002927int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002928{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002929 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002930 bool changed = false;
2931 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002932
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002933 if (discoverable) {
2934 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2935 changed = true;
2936 } else {
2937 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2938 changed = true;
2939 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002940
Johan Hedberged9b5f22012-02-21 20:47:06 +02002941 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002942 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002943
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002944 if (changed)
2945 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002946
Johan Hedberg73f22f62010-12-29 16:00:25 +02002947 if (match.sk)
2948 sock_put(match.sk);
2949
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002950 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002951}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002952
Johan Hedberg744cf192011-11-08 20:40:14 +02002953int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002954{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002955 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002956 bool changed = false;
2957 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002958
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002959 if (connectable) {
2960 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2961 changed = true;
2962 } else {
2963 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2964 changed = true;
2965 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002966
Johan Hedberged9b5f22012-02-21 20:47:06 +02002967 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002968 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002969
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002970 if (changed)
2971 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002972
2973 if (match.sk)
2974 sock_put(match.sk);
2975
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002976 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002977}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002978
Johan Hedberg744cf192011-11-08 20:40:14 +02002979int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002980{
Johan Hedbergca69b792011-11-11 18:10:00 +02002981 u8 mgmt_err = mgmt_status(status);
2982
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002983 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002984 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002985 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002986
2987 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002988 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002989 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002990
2991 return 0;
2992}
2993
Cristian Chilipirea53168e52012-05-09 08:44:52 +03002994int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2995 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002996{
Johan Hedberg86742e12011-11-07 23:13:38 +02002997 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002998
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002999 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003000
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003001 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003002 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003003 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003004 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003005 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003006 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003007
Johan Hedberg744cf192011-11-08 20:40:14 +02003008 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003009}
Johan Hedbergf7520542011-01-20 12:34:39 +02003010
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003011int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3012{
3013 struct mgmt_ev_new_long_term_key ev;
3014
3015 memset(&ev, 0, sizeof(ev));
3016
3017 ev.store_hint = persistent;
3018 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003019 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003020 ev.key.authenticated = key->authenticated;
3021 ev.key.enc_size = key->enc_size;
3022 ev.key.ediv = key->ediv;
3023
3024 if (key->type == HCI_SMP_LTK)
3025 ev.key.master = 1;
3026
3027 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3028 memcpy(ev.key.val, key->val, sizeof(key->val));
3029
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003030 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3031 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003032}
3033
Johan Hedbergafc747a2012-01-15 18:11:07 +02003034int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003035 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3036 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003037{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003038 char buf[512];
3039 struct mgmt_ev_device_connected *ev = (void *) buf;
3040 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003041
Johan Hedbergb644ba32012-01-17 21:48:47 +02003042 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003043 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003044
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003045 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003046
Johan Hedbergb644ba32012-01-17 21:48:47 +02003047 if (name_len > 0)
3048 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003049 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003050
3051 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003052 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003053 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003054
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003055 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003056
3057 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003058 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003059}
3060
Johan Hedberg8962ee72011-01-20 12:40:27 +02003061static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3062{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003063 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003064 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003065 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003066
Johan Hedberg88c3df12012-02-09 14:27:38 +02003067 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3068 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003069
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003070 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003071 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003072
3073 *sk = cmd->sk;
3074 sock_hold(*sk);
3075
Johan Hedberga664b5b2011-02-19 12:06:02 -03003076 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003077}
3078
Johan Hedberg124f6e32012-02-09 13:50:12 +02003079static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003080{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003081 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003082 struct mgmt_cp_unpair_device *cp = cmd->param;
3083 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003084
3085 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003086 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3087 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003088
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003089 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3090
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003091 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003092
3093 mgmt_pending_remove(cmd);
3094}
3095
Johan Hedbergafc747a2012-01-15 18:11:07 +02003096int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003097 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003098{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003099 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003100 struct sock *sk = NULL;
3101 int err;
3102
Johan Hedberg744cf192011-11-08 20:40:14 +02003103 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003104
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003105 bacpy(&ev.addr.bdaddr, bdaddr);
3106 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3107 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003108
Johan Hedbergafc747a2012-01-15 18:11:07 +02003109 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003110 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003111
3112 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003113 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003114
Johan Hedberg124f6e32012-02-09 13:50:12 +02003115 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003116 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003117
Johan Hedberg8962ee72011-01-20 12:40:27 +02003118 return err;
3119}
3120
Johan Hedberg88c3df12012-02-09 14:27:38 +02003121int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003122 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003123{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003124 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003125 struct pending_cmd *cmd;
3126 int err;
3127
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003128 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003129 if (!cmd)
3130 return -ENOENT;
3131
Johan Hedberg88c3df12012-02-09 14:27:38 +02003132 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003133 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003134
Johan Hedberg88c3df12012-02-09 14:27:38 +02003135 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003136 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003137
Johan Hedberga664b5b2011-02-19 12:06:02 -03003138 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003139
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003140 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003141 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003142 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003143}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003144
Johan Hedberg48264f02011-11-09 13:58:58 +02003145int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003146 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003147{
3148 struct mgmt_ev_connect_failed ev;
3149
Johan Hedberg4c659c32011-11-07 23:13:39 +02003150 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003151 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003152 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003153
Johan Hedberg744cf192011-11-08 20:40:14 +02003154 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003155}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003156
Johan Hedberg744cf192011-11-08 20:40:14 +02003157int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003158{
3159 struct mgmt_ev_pin_code_request ev;
3160
Johan Hedbergd8457692012-02-17 14:24:57 +02003161 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003162 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003163 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003164
Johan Hedberg744cf192011-11-08 20:40:14 +02003165 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003166 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003167}
3168
Johan Hedberg744cf192011-11-08 20:40:14 +02003169int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003170 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003171{
3172 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003173 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003174 int err;
3175
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003176 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003177 if (!cmd)
3178 return -ENOENT;
3179
Johan Hedbergd8457692012-02-17 14:24:57 +02003180 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003181 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003182
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003183 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003184 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003185
Johan Hedberga664b5b2011-02-19 12:06:02 -03003186 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003187
3188 return err;
3189}
3190
Johan Hedberg744cf192011-11-08 20:40:14 +02003191int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003192 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003193{
3194 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003195 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003196 int err;
3197
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003198 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003199 if (!cmd)
3200 return -ENOENT;
3201
Johan Hedbergd8457692012-02-17 14:24:57 +02003202 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003203 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003204
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003205 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003206 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003207
Johan Hedberga664b5b2011-02-19 12:06:02 -03003208 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003209
3210 return err;
3211}
Johan Hedberga5c29682011-02-19 12:05:57 -03003212
Johan Hedberg744cf192011-11-08 20:40:14 +02003213int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003214 u8 link_type, u8 addr_type, __le32 value,
3215 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003216{
3217 struct mgmt_ev_user_confirm_request ev;
3218
Johan Hedberg744cf192011-11-08 20:40:14 +02003219 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003220
Johan Hedberg272d90d2012-02-09 15:26:12 +02003221 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003222 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003223 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003224 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003225
Johan Hedberg744cf192011-11-08 20:40:14 +02003226 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003227 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003228}
3229
Johan Hedberg272d90d2012-02-09 15:26:12 +02003230int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003231 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003232{
3233 struct mgmt_ev_user_passkey_request ev;
3234
3235 BT_DBG("%s", hdev->name);
3236
Johan Hedberg272d90d2012-02-09 15:26:12 +02003237 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003238 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003239
3240 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003241 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003242}
3243
Brian Gix0df4c182011-11-16 13:53:13 -08003244static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003245 u8 link_type, u8 addr_type, u8 status,
3246 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003247{
3248 struct pending_cmd *cmd;
3249 struct mgmt_rp_user_confirm_reply rp;
3250 int err;
3251
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003252 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003253 if (!cmd)
3254 return -ENOENT;
3255
Johan Hedberg272d90d2012-02-09 15:26:12 +02003256 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003257 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003258 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003259 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003260
Johan Hedberga664b5b2011-02-19 12:06:02 -03003261 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003262
3263 return err;
3264}
3265
Johan Hedberg744cf192011-11-08 20:40:14 +02003266int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003267 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003268{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003269 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003270 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003271}
3272
Johan Hedberg272d90d2012-02-09 15:26:12 +02003273int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003274 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003275{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003276 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003277 status,
3278 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003279}
Johan Hedberg2a611692011-02-19 12:06:00 -03003280
Brian Gix604086b2011-11-23 08:28:33 -08003281int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003282 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003283{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003284 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003285 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003286}
3287
Johan Hedberg272d90d2012-02-09 15:26:12 +02003288int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003289 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003290{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003291 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003292 status,
3293 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003294}
3295
Johan Hedberg92a25252012-09-06 18:39:26 +03003296int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3297 u8 link_type, u8 addr_type, u32 passkey,
3298 u8 entered)
3299{
3300 struct mgmt_ev_passkey_notify ev;
3301
3302 BT_DBG("%s", hdev->name);
3303
3304 bacpy(&ev.addr.bdaddr, bdaddr);
3305 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3306 ev.passkey = __cpu_to_le32(passkey);
3307 ev.entered = entered;
3308
3309 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3310}
3311
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003312int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003313 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003314{
3315 struct mgmt_ev_auth_failed ev;
3316
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003317 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003318 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003319 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003320
Johan Hedberg744cf192011-11-08 20:40:14 +02003321 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003322}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003323
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003324int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3325{
3326 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003327 bool changed = false;
3328 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003329
3330 if (status) {
3331 u8 mgmt_err = mgmt_status(status);
3332 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003333 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003334 return 0;
3335 }
3336
Johan Hedberg47990ea2012-02-22 11:58:37 +02003337 if (test_bit(HCI_AUTH, &hdev->flags)) {
3338 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3339 changed = true;
3340 } else {
3341 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3342 changed = true;
3343 }
3344
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003345 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003346 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003347
Johan Hedberg47990ea2012-02-22 11:58:37 +02003348 if (changed)
3349 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003350
3351 if (match.sk)
3352 sock_put(match.sk);
3353
3354 return err;
3355}
3356
Johan Hedbergcacaf522012-02-21 00:52:42 +02003357static int clear_eir(struct hci_dev *hdev)
3358{
3359 struct hci_cp_write_eir cp;
3360
3361 if (!(hdev->features[6] & LMP_EXT_INQ))
3362 return 0;
3363
Johan Hedbergc80da272012-02-22 15:38:48 +02003364 memset(hdev->eir, 0, sizeof(hdev->eir));
3365
Johan Hedbergcacaf522012-02-21 00:52:42 +02003366 memset(&cp, 0, sizeof(cp));
3367
3368 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3369}
3370
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003371int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003372{
3373 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003374 bool changed = false;
3375 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003376
3377 if (status) {
3378 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003379
3380 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003381 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003382 err = new_settings(hdev, NULL);
3383
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003384 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3385 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003386
3387 return err;
3388 }
3389
3390 if (enable) {
3391 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3392 changed = true;
3393 } else {
3394 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3395 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003396 }
3397
3398 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3399
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003400 if (changed)
3401 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003402
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003403 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003404 sock_put(match.sk);
3405
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003406 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3407 update_eir(hdev);
3408 else
3409 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003410
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003411 return err;
3412}
3413
Johan Hedberg90e70452012-02-23 23:09:40 +02003414static void class_rsp(struct pending_cmd *cmd, void *data)
3415{
3416 struct cmd_lookup *match = data;
3417
3418 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003419 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003420
3421 list_del(&cmd->list);
3422
3423 if (match->sk == NULL) {
3424 match->sk = cmd->sk;
3425 sock_hold(match->sk);
3426 }
3427
3428 mgmt_pending_free(cmd);
3429}
3430
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003431int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003432 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003433{
Johan Hedberg90e70452012-02-23 23:09:40 +02003434 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3435 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003436
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003437 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3438
Johan Hedberg90e70452012-02-23 23:09:40 +02003439 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3440 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3441 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3442
3443 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003444 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3445 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003446
3447 if (match.sk)
3448 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003449
3450 return err;
3451}
3452
Johan Hedberg744cf192011-11-08 20:40:14 +02003453int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003454{
3455 struct pending_cmd *cmd;
3456 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003457 bool changed = false;
3458 int err = 0;
3459
3460 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3461 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3462 changed = true;
3463 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003464
3465 memset(&ev, 0, sizeof(ev));
3466 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003467 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003468
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003469 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003470 if (!cmd)
3471 goto send_event;
3472
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003473 /* Always assume that either the short or the complete name has
3474 * changed if there was a pending mgmt command */
3475 changed = true;
3476
Johan Hedbergb312b1612011-03-16 14:29:37 +02003477 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003478 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003479 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003480 goto failed;
3481 }
3482
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003483 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003484 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003485 if (err < 0)
3486 goto failed;
3487
3488send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003489 if (changed)
3490 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003491 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003492
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003493 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003494
3495failed:
3496 if (cmd)
3497 mgmt_pending_remove(cmd);
3498 return err;
3499}
Szymon Jancc35938b2011-03-22 13:12:21 +01003500
Johan Hedberg744cf192011-11-08 20:40:14 +02003501int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003502 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003503{
3504 struct pending_cmd *cmd;
3505 int err;
3506
Johan Hedberg744cf192011-11-08 20:40:14 +02003507 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003508
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003509 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003510 if (!cmd)
3511 return -ENOENT;
3512
3513 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003514 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3515 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003516 } else {
3517 struct mgmt_rp_read_local_oob_data rp;
3518
3519 memcpy(rp.hash, hash, sizeof(rp.hash));
3520 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3521
Johan Hedberg744cf192011-11-08 20:40:14 +02003522 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003523 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3524 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003525 }
3526
3527 mgmt_pending_remove(cmd);
3528
3529 return err;
3530}
Johan Hedberge17acd42011-03-30 23:57:16 +03003531
Johan Hedberg06199cf2012-02-22 16:37:11 +02003532int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3533{
3534 struct cmd_lookup match = { NULL, hdev };
3535 bool changed = false;
3536 int err = 0;
3537
3538 if (status) {
3539 u8 mgmt_err = mgmt_status(status);
3540
3541 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003542 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003543 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003544
Szymon Jancd97dcb62012-03-16 16:02:56 +01003545 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3546 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003547
3548 return err;
3549 }
3550
3551 if (enable) {
3552 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3553 changed = true;
3554 } else {
3555 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3556 changed = true;
3557 }
3558
3559 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3560
3561 if (changed)
3562 err = new_settings(hdev, match.sk);
3563
3564 if (match.sk)
3565 sock_put(match.sk);
3566
3567 return err;
3568}
3569
Johan Hedberg48264f02011-11-09 13:58:58 +02003570int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003571 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3572 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003573{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003574 char buf[512];
3575 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003576 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003577
Johan Hedberg1dc06092012-01-15 21:01:23 +02003578 /* Leave 5 bytes for a potential CoD field */
3579 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003580 return -EINVAL;
3581
Johan Hedberg1dc06092012-01-15 21:01:23 +02003582 memset(buf, 0, sizeof(buf));
3583
Johan Hedberge319d2e2012-01-15 19:51:59 +02003584 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003585 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003586 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003587 if (cfm_name)
Andrei Emeltchenko33cef262012-06-18 13:03:46 +03003588 ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003589 if (!ssp)
Andrei Emeltchenko33cef262012-06-18 13:03:46 +03003590 ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003591
Johan Hedberg1dc06092012-01-15 21:01:23 +02003592 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003593 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003594
Johan Hedberg1dc06092012-01-15 21:01:23 +02003595 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3596 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003597 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003598
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003599 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003600 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003601
Johan Hedberge319d2e2012-01-15 19:51:59 +02003602 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003603}
Johan Hedberga88a9652011-03-30 13:18:12 +03003604
Johan Hedbergb644ba32012-01-17 21:48:47 +02003605int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003606 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003607{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003608 struct mgmt_ev_device_found *ev;
3609 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3610 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003611
Johan Hedbergb644ba32012-01-17 21:48:47 +02003612 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003613
Johan Hedbergb644ba32012-01-17 21:48:47 +02003614 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003615
Johan Hedbergb644ba32012-01-17 21:48:47 +02003616 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003617 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003618 ev->rssi = rssi;
3619
3620 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003621 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003622
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003623 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003624
Johan Hedberg053c7e02012-02-04 00:06:00 +02003625 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003626 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003627}
Johan Hedberg314b2382011-04-27 10:29:57 -04003628
Andre Guedes7a135102011-11-09 17:14:25 -03003629int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003630{
3631 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003632 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003633 int err;
3634
Andre Guedes203159d2012-02-13 15:41:01 -03003635 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3636
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003637 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003638 if (!cmd)
3639 return -ENOENT;
3640
Johan Hedbergf808e162012-02-19 12:52:07 +02003641 type = hdev->discovery.type;
3642
3643 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003644 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003645 mgmt_pending_remove(cmd);
3646
3647 return err;
3648}
3649
Andre Guedese6d465c2011-11-09 17:14:26 -03003650int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3651{
3652 struct pending_cmd *cmd;
3653 int err;
3654
3655 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3656 if (!cmd)
3657 return -ENOENT;
3658
Johan Hedbergd9306502012-02-20 23:25:18 +02003659 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003660 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003661 mgmt_pending_remove(cmd);
3662
3663 return err;
3664}
Johan Hedberg314b2382011-04-27 10:29:57 -04003665
Johan Hedberg744cf192011-11-08 20:40:14 +02003666int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003667{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003668 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003669 struct pending_cmd *cmd;
3670
Andre Guedes343fb142011-11-22 17:14:19 -03003671 BT_DBG("%s discovering %u", hdev->name, discovering);
3672
Johan Hedberg164a6e72011-11-01 17:06:44 +02003673 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003674 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003675 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003676 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003677
3678 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003679 u8 type = hdev->discovery.type;
3680
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003681 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3682 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003683 mgmt_pending_remove(cmd);
3684 }
3685
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003686 memset(&ev, 0, sizeof(ev));
3687 ev.type = hdev->discovery.type;
3688 ev.discovering = discovering;
3689
3690 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003691}
Antti Julku5e762442011-08-25 16:48:02 +03003692
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003693int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003694{
3695 struct pending_cmd *cmd;
3696 struct mgmt_ev_device_blocked ev;
3697
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003698 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003699
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003700 bacpy(&ev.addr.bdaddr, bdaddr);
3701 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003702
Johan Hedberg744cf192011-11-08 20:40:14 +02003703 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003704 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003705}
3706
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003707int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003708{
3709 struct pending_cmd *cmd;
3710 struct mgmt_ev_device_unblocked ev;
3711
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003712 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003713
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003714 bacpy(&ev.addr.bdaddr, bdaddr);
3715 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003716
Johan Hedberg744cf192011-11-08 20:40:14 +02003717 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003718 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003719}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003720
3721module_param(enable_hs, bool, 0644);
3722MODULE_PARM_DESC(enable_hs, "Enable High Speed support");