blob: 37add53ce613bf9c7e25dcb4e0e422913e65f096 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg23b3b132012-09-06 18:39:27 +030038#define MGMT_REVISION 2
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Andre Guedes3fd24152012-02-03 17:48:01 -0300105/*
106 * These LE scan and inquiry parameters were chosen according to LE General
107 * Discovery Procedure specification.
108 */
109#define LE_SCAN_TYPE 0x01
110#define LE_SCAN_WIN 0x12
111#define LE_SCAN_INT 0x12
112#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300113#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300114
Andre Guedese8777522012-02-03 17:48:02 -0300115#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300116#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300117
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800118#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200119
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200120#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
121 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
122
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200123struct pending_cmd {
124 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200125 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200126 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100127 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200128 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300129 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200130};
131
Johan Hedbergca69b792011-11-11 18:10:00 +0200132/* HCI to MGMT error code conversion table */
133static u8 mgmt_status_table[] = {
134 MGMT_STATUS_SUCCESS,
135 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
136 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
137 MGMT_STATUS_FAILED, /* Hardware Failure */
138 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
139 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
140 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
141 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
142 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
143 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
145 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
146 MGMT_STATUS_BUSY, /* Command Disallowed */
147 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
148 MGMT_STATUS_REJECTED, /* Rejected Security */
149 MGMT_STATUS_REJECTED, /* Rejected Personal */
150 MGMT_STATUS_TIMEOUT, /* Host Timeout */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
153 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
154 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
155 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
156 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
157 MGMT_STATUS_BUSY, /* Repeated Attempts */
158 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
159 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
160 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
161 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
162 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
163 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
164 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
165 MGMT_STATUS_FAILED, /* Unspecified Error */
166 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
167 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
168 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
169 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
170 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
171 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
172 MGMT_STATUS_FAILED, /* Unit Link Key Used */
173 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
174 MGMT_STATUS_TIMEOUT, /* Instant Passed */
175 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
176 MGMT_STATUS_FAILED, /* Transaction Collision */
177 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
178 MGMT_STATUS_REJECTED, /* QoS Rejected */
179 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
180 MGMT_STATUS_REJECTED, /* Insufficient Security */
181 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
182 MGMT_STATUS_BUSY, /* Role Switch Pending */
183 MGMT_STATUS_FAILED, /* Slot Violation */
184 MGMT_STATUS_FAILED, /* Role Switch Failed */
185 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
186 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
187 MGMT_STATUS_BUSY, /* Host Busy Pairing */
188 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
189 MGMT_STATUS_BUSY, /* Controller Busy */
190 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
191 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
192 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
193 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
194 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
195};
196
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300197bool mgmt_valid_hdev(struct hci_dev *hdev)
198{
199 return hdev->dev_type == HCI_BREDR;
200}
201
Johan Hedbergca69b792011-11-11 18:10:00 +0200202static u8 mgmt_status(u8 hci_status)
203{
204 if (hci_status < ARRAY_SIZE(mgmt_status_table))
205 return mgmt_status_table[hci_status];
206
207 return MGMT_STATUS_FAILED;
208}
209
Szymon Janc4e51eae2011-02-25 19:05:48 +0100210static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200211{
212 struct sk_buff *skb;
213 struct mgmt_hdr *hdr;
214 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300215 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200216
Szymon Janc34eb5252011-02-28 14:10:08 +0100217 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200218
Andre Guedes790eff42012-06-07 19:05:46 -0300219 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 if (!skb)
221 return -ENOMEM;
222
223 hdr = (void *) skb_put(skb, sizeof(*hdr));
224
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530225 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100226 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200227 hdr->len = cpu_to_le16(sizeof(*ev));
228
229 ev = (void *) skb_put(skb, sizeof(*ev));
230 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200231 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 err = sock_queue_rcv_skb(sk, skb);
234 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200235 kfree_skb(skb);
236
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300237 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200238}
239
Johan Hedbergaee9b212012-02-18 15:07:59 +0200240static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300241 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200242{
243 struct sk_buff *skb;
244 struct mgmt_hdr *hdr;
245 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300246 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
248 BT_DBG("sock %p", sk);
249
Andre Guedes790eff42012-06-07 19:05:46 -0300250 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251 if (!skb)
252 return -ENOMEM;
253
254 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200255
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530256 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100257 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200258 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200259
Johan Hedberga38528f2011-01-22 06:46:43 +0200260 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200261 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200262 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100263
264 if (rp)
265 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200266
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 err = sock_queue_rcv_skb(sk, skb);
268 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200269 kfree_skb(skb);
270
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100271 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200272}
273
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
275 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200276{
277 struct mgmt_rp_read_version rp;
278
279 BT_DBG("sock %p", sk);
280
281 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200282 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200283
Johan Hedbergaee9b212012-02-18 15:07:59 +0200284 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200286}
287
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300288static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
289 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200290{
291 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200292 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
293 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200294 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295 size_t rp_size;
296 int i, err;
297
298 BT_DBG("sock %p", sk);
299
300 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
301
302 rp = kmalloc(rp_size, GFP_KERNEL);
303 if (!rp)
304 return -ENOMEM;
305
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200306 rp->num_commands = __constant_cpu_to_le16(num_commands);
307 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200308
309 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
310 put_unaligned_le16(mgmt_commands[i], opcode);
311
312 for (i = 0; i < num_events; i++, opcode++)
313 put_unaligned_le16(mgmt_events[i], opcode);
314
Johan Hedbergaee9b212012-02-18 15:07:59 +0200315 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300316 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200317 kfree(rp);
318
319 return err;
320}
321
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300322static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
323 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200326 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300329 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330
331 BT_DBG("sock %p", sk);
332
333 read_lock(&hci_dev_list_lock);
334
335 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300336 list_for_each_entry(d, &hci_dev_list, list) {
337 if (!mgmt_valid_hdev(d))
338 continue;
339
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340 count++;
341 }
342
Johan Hedberga38528f2011-01-22 06:46:43 +0200343 rp_len = sizeof(*rp) + (2 * count);
344 rp = kmalloc(rp_len, GFP_ATOMIC);
345 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100346 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200347 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100348 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349
Johan Hedberg476e44c2012-10-19 20:10:46 +0300350 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200351 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200352 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200353 continue;
354
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300355 if (!mgmt_valid_hdev(d))
356 continue;
357
Johan Hedberg476e44c2012-10-19 20:10:46 +0300358 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359 BT_DBG("Added hci%u", d->id);
360 }
361
Johan Hedberg476e44c2012-10-19 20:10:46 +0300362 rp->num_controllers = cpu_to_le16(count);
363 rp_len = sizeof(*rp) + (2 * count);
364
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200365 read_unlock(&hci_dev_list_lock);
366
Johan Hedbergaee9b212012-02-18 15:07:59 +0200367 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300368 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200369
Johan Hedberga38528f2011-01-22 06:46:43 +0200370 kfree(rp);
371
372 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200373}
374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200376{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200377 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200378
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200381
Andre Guedes9a1a1992012-07-24 15:03:48 -0300382 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200383 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200384
Andre Guedesed3fa312012-07-24 15:03:46 -0300385 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300386 settings |= MGMT_SETTING_CONNECTABLE;
387 settings |= MGMT_SETTING_FAST_CONNECTABLE;
388 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389 settings |= MGMT_SETTING_BREDR;
390 settings |= MGMT_SETTING_LINK_SECURITY;
391 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200392
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100393 if (enable_hs)
394 settings |= MGMT_SETTING_HS;
395
Andre Guedesc383ddc2012-07-24 15:03:47 -0300396 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200397 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200398
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 return settings;
400}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200401
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402static u32 get_current_settings(struct hci_dev *hdev)
403{
404 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200405
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200406 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100407 settings |= MGMT_SETTING_POWERED;
408
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200409 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_CONNECTABLE;
411
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200412 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_DISCOVERABLE;
414
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200415 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_PAIRABLE;
417
Andre Guedesed3fa312012-07-24 15:03:46 -0300418 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_BREDR;
420
Johan Hedberg06199cf2012-02-22 16:37:11 +0200421 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg47990ea2012-02-22 11:58:37 +0200424 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200426
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200427 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200428 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200429
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200430 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
431 settings |= MGMT_SETTING_HS;
432
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200433 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200434}
435
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300436#define PNP_INFO_SVCLASS_ID 0x1200
437
438static u8 bluetooth_base_uuid[] = {
439 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
440 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
441};
442
443static u16 get_uuid16(u8 *uuid128)
444{
445 u32 val;
446 int i;
447
448 for (i = 0; i < 12; i++) {
449 if (bluetooth_base_uuid[i] != uuid128[i])
450 return 0;
451 }
452
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200453 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300454 if (val > 0xffff)
455 return 0;
456
457 return (u16) val;
458}
459
460static void create_eir(struct hci_dev *hdev, u8 *data)
461{
462 u8 *ptr = data;
463 u16 eir_len = 0;
464 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
465 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200466 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300467 size_t name_len;
468
469 name_len = strlen(hdev->dev_name);
470
471 if (name_len > 0) {
472 /* EIR Data type */
473 if (name_len > 48) {
474 name_len = 48;
475 ptr[1] = EIR_NAME_SHORT;
476 } else
477 ptr[1] = EIR_NAME_COMPLETE;
478
479 /* EIR Data length */
480 ptr[0] = name_len + 1;
481
482 memcpy(ptr + 2, hdev->dev_name, name_len);
483
484 eir_len += (name_len + 2);
485 ptr += (name_len + 2);
486 }
487
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100488 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700489 ptr[0] = 2;
490 ptr[1] = EIR_TX_POWER;
491 ptr[2] = (u8) hdev->inq_tx_power;
492
493 eir_len += 3;
494 ptr += 3;
495 }
496
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700497 if (hdev->devid_source > 0) {
498 ptr[0] = 9;
499 ptr[1] = EIR_DEVICE_ID;
500
501 put_unaligned_le16(hdev->devid_source, ptr + 2);
502 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
503 put_unaligned_le16(hdev->devid_product, ptr + 6);
504 put_unaligned_le16(hdev->devid_version, ptr + 8);
505
506 eir_len += 10;
507 ptr += 10;
508 }
509
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300510 memset(uuid16_list, 0, sizeof(uuid16_list));
511
512 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200513 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300514 u16 uuid16;
515
516 uuid16 = get_uuid16(uuid->uuid);
517 if (uuid16 == 0)
518 return;
519
520 if (uuid16 < 0x1100)
521 continue;
522
523 if (uuid16 == PNP_INFO_SVCLASS_ID)
524 continue;
525
526 /* Stop if not enough space to put next UUID */
527 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
528 truncated = 1;
529 break;
530 }
531
532 /* Check for duplicates */
533 for (i = 0; uuid16_list[i] != 0; i++)
534 if (uuid16_list[i] == uuid16)
535 break;
536
537 if (uuid16_list[i] == 0) {
538 uuid16_list[i] = uuid16;
539 eir_len += sizeof(u16);
540 }
541 }
542
543 if (uuid16_list[0] != 0) {
544 u8 *length = ptr;
545
546 /* EIR Data type */
547 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
548
549 ptr += 2;
550 eir_len += 2;
551
552 for (i = 0; uuid16_list[i] != 0; i++) {
553 *ptr++ = (uuid16_list[i] & 0x00ff);
554 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
555 }
556
557 /* EIR Data length */
558 *length = (i * sizeof(u16)) + 1;
559 }
560}
561
562static int update_eir(struct hci_dev *hdev)
563{
564 struct hci_cp_write_eir cp;
565
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200566 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200567 return 0;
568
Johan Hedberg976eb202012-10-24 21:12:01 +0300569 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300570 return 0;
571
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200572 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300573 return 0;
574
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200575 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300576 return 0;
577
578 memset(&cp, 0, sizeof(cp));
579
580 create_eir(hdev, cp.data);
581
582 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
583 return 0;
584
585 memcpy(hdev->eir, cp.data, sizeof(cp.data));
586
587 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
588}
589
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200590static u8 get_service_classes(struct hci_dev *hdev)
591{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300592 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200593 u8 val = 0;
594
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300595 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200596 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200597
598 return val;
599}
600
601static int update_class(struct hci_dev *hdev)
602{
603 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200604 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200605
606 BT_DBG("%s", hdev->name);
607
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200608 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200609 return 0;
610
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200611 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200612 return 0;
613
614 cod[0] = hdev->minor_class;
615 cod[1] = hdev->major_class;
616 cod[2] = get_service_classes(hdev);
617
618 if (memcmp(cod, hdev->dev_class, 3) == 0)
619 return 0;
620
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200621 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
622 if (err == 0)
623 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
624
625 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200626}
627
Johan Hedberg7d785252011-12-15 00:47:39 +0200628static void service_cache_off(struct work_struct *work)
629{
630 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300631 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200632
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200633 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 return;
635
636 hci_dev_lock(hdev);
637
638 update_eir(hdev);
639 update_class(hdev);
640
641 hci_dev_unlock(hdev);
642}
643
Johan Hedberg6a919082012-02-28 06:17:26 +0200644static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200645{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200646 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200647 return;
648
Johan Hedberg4f87da82012-03-02 19:55:56 +0200649 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200650
Johan Hedberg4f87da82012-03-02 19:55:56 +0200651 /* Non-mgmt controlled devices get this bit set
652 * implicitly so that pairing works for them, however
653 * for mgmt we require user-space to explicitly enable
654 * it
655 */
656 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200657}
658
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200659static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300660 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200661{
662 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200663
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200664 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200665
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300666 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200667
Johan Hedberg03811012010-12-08 00:21:06 +0200668 memset(&rp, 0, sizeof(rp));
669
Johan Hedberg03811012010-12-08 00:21:06 +0200670 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200671
672 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200673 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200674
675 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
676 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
677
678 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200679
680 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200681 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200682
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300683 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200684
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200685 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300686 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200687}
688
689static void mgmt_pending_free(struct pending_cmd *cmd)
690{
691 sock_put(cmd->sk);
692 kfree(cmd->param);
693 kfree(cmd);
694}
695
696static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300697 struct hci_dev *hdev, void *data,
698 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200699{
700 struct pending_cmd *cmd;
701
Andre Guedes12b94562012-06-07 19:05:45 -0300702 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200703 if (!cmd)
704 return NULL;
705
706 cmd->opcode = opcode;
707 cmd->index = hdev->id;
708
Andre Guedes12b94562012-06-07 19:05:45 -0300709 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200710 if (!cmd->param) {
711 kfree(cmd);
712 return NULL;
713 }
714
715 if (data)
716 memcpy(cmd->param, data, len);
717
718 cmd->sk = sk;
719 sock_hold(sk);
720
721 list_add(&cmd->list, &hdev->mgmt_pending);
722
723 return cmd;
724}
725
726static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300727 void (*cb)(struct pending_cmd *cmd,
728 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300729 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200730{
731 struct list_head *p, *n;
732
733 list_for_each_safe(p, n, &hdev->mgmt_pending) {
734 struct pending_cmd *cmd;
735
736 cmd = list_entry(p, struct pending_cmd, list);
737
738 if (opcode > 0 && cmd->opcode != opcode)
739 continue;
740
741 cb(cmd, data);
742 }
743}
744
745static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
746{
747 struct pending_cmd *cmd;
748
749 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
750 if (cmd->opcode == opcode)
751 return cmd;
752 }
753
754 return NULL;
755}
756
757static void mgmt_pending_remove(struct pending_cmd *cmd)
758{
759 list_del(&cmd->list);
760 mgmt_pending_free(cmd);
761}
762
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200763static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200764{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200765 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200766
Johan Hedbergaee9b212012-02-18 15:07:59 +0200767 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300768 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200769}
770
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200771static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300772 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200773{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300774 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200775 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200776 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200777
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200778 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200779
Johan Hedberga7e80f22013-01-09 16:05:19 +0200780 if (cp->val != 0x00 && cp->val != 0x01)
781 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
782 MGMT_STATUS_INVALID_PARAMS);
783
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300784 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200785
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100786 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
787 cancel_delayed_work(&hdev->power_off);
788
789 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200790 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
791 data, len);
792 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100793 goto failed;
794 }
795 }
796
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200797 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200798 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200799 goto failed;
800 }
801
802 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200803 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300804 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200805 goto failed;
806 }
807
808 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
809 if (!cmd) {
810 err = -ENOMEM;
811 goto failed;
812 }
813
814 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200815 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200816 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200817 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200818
819 err = 0;
820
821failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300822 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200823 return err;
824}
825
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300826static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
827 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200828{
829 struct sk_buff *skb;
830 struct mgmt_hdr *hdr;
831
Andre Guedes790eff42012-06-07 19:05:46 -0300832 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200833 if (!skb)
834 return -ENOMEM;
835
836 hdr = (void *) skb_put(skb, sizeof(*hdr));
837 hdr->opcode = cpu_to_le16(event);
838 if (hdev)
839 hdr->index = cpu_to_le16(hdev->id);
840 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530841 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200842 hdr->len = cpu_to_le16(data_len);
843
844 if (data)
845 memcpy(skb_put(skb, data_len), data, data_len);
846
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100847 /* Time stamp */
848 __net_timestamp(skb);
849
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200850 hci_send_to_control(skb, skip_sk);
851 kfree_skb(skb);
852
853 return 0;
854}
855
856static int new_settings(struct hci_dev *hdev, struct sock *skip)
857{
858 __le32 ev;
859
860 ev = cpu_to_le32(get_current_settings(hdev));
861
862 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
863}
864
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200865static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300866 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200867{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300868 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200869 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200870 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200871 u8 scan;
872 int err;
873
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200874 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200875
Johan Hedberg33c525c2012-10-24 21:11:58 +0300876 if (!lmp_bredr_capable(hdev))
877 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
878 MGMT_STATUS_NOT_SUPPORTED);
879
Johan Hedberga7e80f22013-01-09 16:05:19 +0200880 if (cp->val != 0x00 && cp->val != 0x01)
881 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
882 MGMT_STATUS_INVALID_PARAMS);
883
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700884 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100885 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200886 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300887 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200888
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300889 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200890
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200891 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200892 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300893 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200894 goto failed;
895 }
896
897 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300898 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200899 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300900 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200901 goto failed;
902 }
903
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200904 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200905 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300906 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200907 goto failed;
908 }
909
910 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200911 bool changed = false;
912
913 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
914 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
915 changed = true;
916 }
917
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200918 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200919 if (err < 0)
920 goto failed;
921
922 if (changed)
923 err = new_settings(hdev, sk);
924
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200925 goto failed;
926 }
927
928 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100929 if (hdev->discov_timeout > 0) {
930 cancel_delayed_work(&hdev->discov_off);
931 hdev->discov_timeout = 0;
932 }
933
934 if (cp->val && timeout > 0) {
935 hdev->discov_timeout = timeout;
936 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
937 msecs_to_jiffies(hdev->discov_timeout * 1000));
938 }
939
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200940 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200941 goto failed;
942 }
943
944 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
945 if (!cmd) {
946 err = -ENOMEM;
947 goto failed;
948 }
949
950 scan = SCAN_PAGE;
951
952 if (cp->val)
953 scan |= SCAN_INQUIRY;
954 else
955 cancel_delayed_work(&hdev->discov_off);
956
957 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
958 if (err < 0)
959 mgmt_pending_remove(cmd);
960
Johan Hedberg03811012010-12-08 00:21:06 +0200961 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200963
964failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300965 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200966 return err;
967}
968
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200969static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300970 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200971{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300972 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200973 struct pending_cmd *cmd;
974 u8 scan;
975 int err;
976
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200977 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200978
Johan Hedberg33c525c2012-10-24 21:11:58 +0300979 if (!lmp_bredr_capable(hdev))
980 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
981 MGMT_STATUS_NOT_SUPPORTED);
982
Johan Hedberga7e80f22013-01-09 16:05:19 +0200983 if (cp->val != 0x00 && cp->val != 0x01)
984 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
985 MGMT_STATUS_INVALID_PARAMS);
986
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300987 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200988
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200989 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200990 bool changed = false;
991
992 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
993 changed = true;
994
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200995 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200996 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200997 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200998 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
999 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1000 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001001
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001002 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001003 if (err < 0)
1004 goto failed;
1005
1006 if (changed)
1007 err = new_settings(hdev, sk);
1008
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009 goto failed;
1010 }
1011
1012 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001013 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001014 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001015 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016 goto failed;
1017 }
1018
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001019 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001020 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001021 goto failed;
1022 }
1023
1024 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1025 if (!cmd) {
1026 err = -ENOMEM;
1027 goto failed;
1028 }
1029
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001030 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001032 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001033 scan = 0;
1034
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001035 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001036 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001037 cancel_delayed_work(&hdev->discov_off);
1038 }
1039
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1041 if (err < 0)
1042 mgmt_pending_remove(cmd);
1043
1044failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001045 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046 return err;
1047}
1048
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001049static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001050 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001051{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001052 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001053 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001055 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001056
Johan Hedberga7e80f22013-01-09 16:05:19 +02001057 if (cp->val != 0x00 && cp->val != 0x01)
1058 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1059 MGMT_STATUS_INVALID_PARAMS);
1060
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001061 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001062
1063 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001064 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001065 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001066 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001067
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001068 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001069 if (err < 0)
1070 goto failed;
1071
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001072 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001073
1074failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001075 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001076 return err;
1077}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001078
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001079static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1080 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001081{
1082 struct mgmt_mode *cp = data;
1083 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001084 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001085 int err;
1086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001087 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001088
Johan Hedberg33c525c2012-10-24 21:11:58 +03001089 if (!lmp_bredr_capable(hdev))
1090 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1091 MGMT_STATUS_NOT_SUPPORTED);
1092
Johan Hedberga7e80f22013-01-09 16:05:19 +02001093 if (cp->val != 0x00 && cp->val != 0x01)
1094 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1095 MGMT_STATUS_INVALID_PARAMS);
1096
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001097 hci_dev_lock(hdev);
1098
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001099 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001100 bool changed = false;
1101
1102 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001103 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001104 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1105 changed = true;
1106 }
1107
1108 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1109 if (err < 0)
1110 goto failed;
1111
1112 if (changed)
1113 err = new_settings(hdev, sk);
1114
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001115 goto failed;
1116 }
1117
1118 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001119 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001120 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001121 goto failed;
1122 }
1123
1124 val = !!cp->val;
1125
1126 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1127 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1128 goto failed;
1129 }
1130
1131 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1132 if (!cmd) {
1133 err = -ENOMEM;
1134 goto failed;
1135 }
1136
1137 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1138 if (err < 0) {
1139 mgmt_pending_remove(cmd);
1140 goto failed;
1141 }
1142
1143failed:
1144 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001145 return err;
1146}
1147
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001148static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001149{
1150 struct mgmt_mode *cp = data;
1151 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001152 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001153 int err;
1154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001155 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001156
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001157 if (!lmp_ssp_capable(hdev))
1158 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1159 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001160
Johan Hedberga7e80f22013-01-09 16:05:19 +02001161 if (cp->val != 0x00 && cp->val != 0x01)
1162 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1163 MGMT_STATUS_INVALID_PARAMS);
1164
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001165 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001166
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001167 val = !!cp->val;
1168
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001169 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001170 bool changed = false;
1171
1172 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1173 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1174 changed = true;
1175 }
1176
1177 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1178 if (err < 0)
1179 goto failed;
1180
1181 if (changed)
1182 err = new_settings(hdev, sk);
1183
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001184 goto failed;
1185 }
1186
1187 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001188 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1189 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001190 goto failed;
1191 }
1192
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001193 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1194 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1195 goto failed;
1196 }
1197
1198 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1199 if (!cmd) {
1200 err = -ENOMEM;
1201 goto failed;
1202 }
1203
1204 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1205 if (err < 0) {
1206 mgmt_pending_remove(cmd);
1207 goto failed;
1208 }
1209
1210failed:
1211 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001212 return err;
1213}
1214
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001215static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001216{
1217 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001218
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001219 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001220
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001221 if (!enable_hs)
1222 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001223 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001224
Johan Hedberga7e80f22013-01-09 16:05:19 +02001225 if (cp->val != 0x00 && cp->val != 0x01)
1226 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1227 MGMT_STATUS_INVALID_PARAMS);
1228
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001229 if (cp->val)
1230 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1231 else
1232 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1233
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001234 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001235}
1236
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001237static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001238{
1239 struct mgmt_mode *cp = data;
1240 struct hci_cp_write_le_host_supported hci_cp;
1241 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001242 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001243 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001245 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001246
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001247 if (!lmp_le_capable(hdev))
1248 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1249 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001250
Johan Hedberga7e80f22013-01-09 16:05:19 +02001251 if (cp->val != 0x00 && cp->val != 0x01)
1252 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1253 MGMT_STATUS_INVALID_PARAMS);
1254
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001255 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001256
1257 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001258 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001259
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001260 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001261 bool changed = false;
1262
1263 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1264 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1265 changed = true;
1266 }
1267
1268 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1269 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001270 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001271
1272 if (changed)
1273 err = new_settings(hdev, sk);
1274
Johan Hedberg1de028c2012-02-29 19:55:35 -08001275 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001276 }
1277
1278 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001279 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001280 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001281 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001282 }
1283
1284 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1285 if (!cmd) {
1286 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001287 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001288 }
1289
1290 memset(&hci_cp, 0, sizeof(hci_cp));
1291
1292 if (val) {
1293 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001294 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001295 }
1296
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001297 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1298 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301299 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001300 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001301
Johan Hedberg1de028c2012-02-29 19:55:35 -08001302unlock:
1303 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001304 return err;
1305}
1306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001307static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001308{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001309 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001310 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001311 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 int err;
1313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001314 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001315
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001316 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001317
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001318 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001319 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001320 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001321 goto failed;
1322 }
1323
Andre Guedes92c4c202012-06-07 19:05:44 -03001324 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325 if (!uuid) {
1326 err = -ENOMEM;
1327 goto failed;
1328 }
1329
1330 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001331 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332
1333 list_add(&uuid->list, &hdev->uuids);
1334
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001335 err = update_class(hdev);
1336 if (err < 0)
1337 goto failed;
1338
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001339 err = update_eir(hdev);
1340 if (err < 0)
1341 goto failed;
1342
Johan Hedberg90e70452012-02-23 23:09:40 +02001343 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001344 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001345 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001346 goto failed;
1347 }
1348
1349 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301350 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001351 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352
1353failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001354 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001355 return err;
1356}
1357
Johan Hedberg24b78d02012-02-23 23:24:30 +02001358static bool enable_service_cache(struct hci_dev *hdev)
1359{
1360 if (!hdev_is_powered(hdev))
1361 return false;
1362
1363 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001364 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001365 return true;
1366 }
1367
1368 return false;
1369}
1370
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001371static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001372 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001373{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001374 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001375 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001376 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001377 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 +02001378 int err, found;
1379
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001380 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001381
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001382 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001383
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001384 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001385 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001386 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001387 goto unlock;
1388 }
1389
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001390 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1391 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001392
Johan Hedberg24b78d02012-02-23 23:24:30 +02001393 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001394 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001395 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001396 goto unlock;
1397 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001398
Johan Hedberg9246a862012-02-23 21:33:16 +02001399 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001400 }
1401
1402 found = 0;
1403
1404 list_for_each_safe(p, n, &hdev->uuids) {
1405 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1406
1407 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1408 continue;
1409
1410 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001411 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001412 found++;
1413 }
1414
1415 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001416 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001417 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001418 goto unlock;
1419 }
1420
Johan Hedberg9246a862012-02-23 21:33:16 +02001421update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001422 err = update_class(hdev);
1423 if (err < 0)
1424 goto unlock;
1425
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001426 err = update_eir(hdev);
1427 if (err < 0)
1428 goto unlock;
1429
Johan Hedberg90e70452012-02-23 23:09:40 +02001430 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001431 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001432 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001433 goto unlock;
1434 }
1435
1436 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301437 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001438 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001439
1440unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001441 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001442 return err;
1443}
1444
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001445static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001446 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001448 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001449 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001450 int err;
1451
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001452 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001453
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001454 if (!lmp_bredr_capable(hdev))
1455 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1456 MGMT_STATUS_NOT_SUPPORTED);
1457
1458 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags))
1459 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1460 MGMT_STATUS_BUSY);
1461
1462 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0)
1463 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1464 MGMT_STATUS_INVALID_PARAMS);
1465
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001466 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001467
1468 hdev->major_class = cp->major;
1469 hdev->minor_class = cp->minor;
1470
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001471 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001472 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001473 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001474 goto unlock;
1475 }
1476
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001477 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001478 hci_dev_unlock(hdev);
1479 cancel_delayed_work_sync(&hdev->service_cache);
1480 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001481 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001482 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001483
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001484 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001485 if (err < 0)
1486 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001487
Johan Hedberg90e70452012-02-23 23:09:40 +02001488 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001489 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001490 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001491 goto unlock;
1492 }
1493
1494 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301495 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001496 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001497
Johan Hedbergb5235a62012-02-21 14:32:24 +02001498unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001499 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001500 return err;
1501}
1502
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001503static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001504 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001505{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001506 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001507 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001508 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001509
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001510 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001511
Johan Hedberg86742e12011-11-07 23:13:38 +02001512 expected_len = sizeof(*cp) + key_count *
1513 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001514 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001515 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001516 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001517 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001518 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001519 }
1520
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001521 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001522 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001524 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001525
1526 hci_link_keys_clear(hdev);
1527
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001528 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001529
1530 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001531 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001532 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001533 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001534
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001535 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001536 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001537
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001538 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001539 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001540 }
1541
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001542 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001543
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001544 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001545
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001546 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001547}
1548
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001549static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001550 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001551{
1552 struct mgmt_ev_device_unpaired ev;
1553
1554 bacpy(&ev.addr.bdaddr, bdaddr);
1555 ev.addr.type = addr_type;
1556
1557 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001558 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001559}
1560
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001561static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001562 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001563{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001564 struct mgmt_cp_unpair_device *cp = data;
1565 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001566 struct hci_cp_disconnect dc;
1567 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001568 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001569 int err;
1570
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001571 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001572
Johan Hedberga8a1d192011-11-10 15:54:38 +02001573 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001574 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1575 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001576
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001577 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001578 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001579 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001580 goto unlock;
1581 }
1582
Andre Guedes591f47f2012-04-24 21:02:49 -03001583 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001584 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1585 else
1586 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001587
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001588 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001589 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001590 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001591 goto unlock;
1592 }
1593
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001594 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001595 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001596 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001597 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001598 else
1599 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001600 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001601 } else {
1602 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001603 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001604
Johan Hedberga8a1d192011-11-10 15:54:38 +02001605 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001606 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001607 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001608 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001609 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001610 }
1611
Johan Hedberg124f6e32012-02-09 13:50:12 +02001612 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001613 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001614 if (!cmd) {
1615 err = -ENOMEM;
1616 goto unlock;
1617 }
1618
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001619 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001620 dc.reason = 0x13; /* Remote User Terminated Connection */
1621 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1622 if (err < 0)
1623 mgmt_pending_remove(cmd);
1624
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001625unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001626 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001627 return err;
1628}
1629
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001630static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001631 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001632{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001633 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001634 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001635 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001636 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001637 int err;
1638
1639 BT_DBG("");
1640
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001641 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001642
1643 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001644 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001645 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001646 goto failed;
1647 }
1648
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001649 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001650 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001651 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001652 goto failed;
1653 }
1654
Andre Guedes591f47f2012-04-24 21:02:49 -03001655 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001656 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1657 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001658 else
1659 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001660
Vishal Agarwalf9607272012-06-13 05:32:43 +05301661 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001662 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001663 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001664 goto failed;
1665 }
1666
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001667 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001668 if (!cmd) {
1669 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001670 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001671 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001672
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001673 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001674 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001675
1676 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1677 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001678 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001679
1680failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001681 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001682 return err;
1683}
1684
Andre Guedes57c14772012-04-24 21:02:50 -03001685static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001686{
1687 switch (link_type) {
1688 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001689 switch (addr_type) {
1690 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001691 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001692
Johan Hedberg48264f02011-11-09 13:58:58 +02001693 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001694 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001695 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001696 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001697
Johan Hedberg4c659c32011-11-07 23:13:39 +02001698 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001699 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001700 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001701 }
1702}
1703
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001704static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1705 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001706{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001707 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001708 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001709 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001710 int err;
1711 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001712
1713 BT_DBG("");
1714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001715 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001716
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001717 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001718 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001719 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001720 goto unlock;
1721 }
1722
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001723 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001724 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1725 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001726 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001727 }
1728
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001729 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001730 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001731 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001732 err = -ENOMEM;
1733 goto unlock;
1734 }
1735
Johan Hedberg2784eb42011-01-21 13:56:35 +02001736 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001737 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001738 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1739 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001740 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001741 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001742 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001743 continue;
1744 i++;
1745 }
1746
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001747 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001748
Johan Hedberg4c659c32011-11-07 23:13:39 +02001749 /* Recalculate length in case of filtered SCO connections, etc */
1750 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001751
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001752 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001753 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001754
Johan Hedberga38528f2011-01-22 06:46:43 +02001755 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001756
1757unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001758 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001759 return err;
1760}
1761
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001762static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001763 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001764{
1765 struct pending_cmd *cmd;
1766 int err;
1767
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001768 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001769 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001770 if (!cmd)
1771 return -ENOMEM;
1772
Johan Hedbergd8457692012-02-17 14:24:57 +02001773 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001774 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001775 if (err < 0)
1776 mgmt_pending_remove(cmd);
1777
1778 return err;
1779}
1780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001781static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001782 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001783{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001784 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001785 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001786 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001787 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001788 int err;
1789
1790 BT_DBG("");
1791
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001792 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001793
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001794 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001795 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001796 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001797 goto failed;
1798 }
1799
Johan Hedbergd8457692012-02-17 14:24:57 +02001800 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001801 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001802 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001803 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001804 goto failed;
1805 }
1806
1807 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001808 struct mgmt_cp_pin_code_neg_reply ncp;
1809
1810 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001811
1812 BT_ERR("PIN code is not 16 bytes long");
1813
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001814 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001815 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001816 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001817 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001818
1819 goto failed;
1820 }
1821
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001822 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001823 if (!cmd) {
1824 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001825 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001826 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001827
Johan Hedbergd8457692012-02-17 14:24:57 +02001828 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001829 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001830 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001831
1832 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1833 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001834 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001835
1836failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001837 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001838 return err;
1839}
1840
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001841static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1842 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001843{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001844 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001845
1846 BT_DBG("");
1847
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001848 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001849
1850 hdev->io_capability = cp->io_capability;
1851
1852 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001853 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001854
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001856
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001857 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1858 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001859}
1860
Gustavo Padovan6039aa72012-05-23 04:04:18 -03001861static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001862{
1863 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001864 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001865
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001866 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001867 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1868 continue;
1869
Johan Hedberge9a416b2011-02-19 12:05:56 -03001870 if (cmd->user_data != conn)
1871 continue;
1872
1873 return cmd;
1874 }
1875
1876 return NULL;
1877}
1878
1879static void pairing_complete(struct pending_cmd *cmd, u8 status)
1880{
1881 struct mgmt_rp_pair_device rp;
1882 struct hci_conn *conn = cmd->user_data;
1883
Johan Hedbergba4e5642011-11-11 00:07:34 +02001884 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001885 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001886
Johan Hedbergaee9b212012-02-18 15:07:59 +02001887 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001888 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889
1890 /* So we don't get further callbacks for this connection */
1891 conn->connect_cfm_cb = NULL;
1892 conn->security_cfm_cb = NULL;
1893 conn->disconn_cfm_cb = NULL;
1894
1895 hci_conn_put(conn);
1896
Johan Hedberga664b5b2011-02-19 12:06:02 -03001897 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898}
1899
1900static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1901{
1902 struct pending_cmd *cmd;
1903
1904 BT_DBG("status %u", status);
1905
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001906 cmd = find_pairing(conn);
1907 if (!cmd)
1908 BT_DBG("Unable to find a pending command");
1909 else
Johan Hedberge2113262012-02-18 15:20:03 +02001910 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911}
1912
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301913static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1914{
1915 struct pending_cmd *cmd;
1916
1917 BT_DBG("status %u", status);
1918
1919 if (!status)
1920 return;
1921
1922 cmd = find_pairing(conn);
1923 if (!cmd)
1924 BT_DBG("Unable to find a pending command");
1925 else
1926 pairing_complete(cmd, mgmt_status(status));
1927}
1928
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001929static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001930 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001931{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001932 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001933 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001934 struct pending_cmd *cmd;
1935 u8 sec_level, auth_type;
1936 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937 int err;
1938
1939 BT_DBG("");
1940
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001941 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001942
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001943 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001944 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001945 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001946 goto unlock;
1947 }
1948
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001949 sec_level = BT_SECURITY_MEDIUM;
1950 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001952 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001953 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001954
Andre Guedes591f47f2012-04-24 21:02:49 -03001955 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001956 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1957 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001958 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001959 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1960 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001961
Johan Hedberg1425acb2011-11-11 00:07:35 +02001962 memset(&rp, 0, sizeof(rp));
1963 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1964 rp.addr.type = cp->addr.type;
1965
Ville Tervo30e76272011-02-22 16:10:53 -03001966 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001967 int status;
1968
1969 if (PTR_ERR(conn) == -EBUSY)
1970 status = MGMT_STATUS_BUSY;
1971 else
1972 status = MGMT_STATUS_CONNECT_FAILED;
1973
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001974 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001975 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001976 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001977 goto unlock;
1978 }
1979
1980 if (conn->connect_cfm_cb) {
1981 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001983 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001984 goto unlock;
1985 }
1986
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001987 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001988 if (!cmd) {
1989 err = -ENOMEM;
1990 hci_conn_put(conn);
1991 goto unlock;
1992 }
1993
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001994 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001995 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001996 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301997 else
1998 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001999
Johan Hedberge9a416b2011-02-19 12:05:56 -03002000 conn->security_cfm_cb = pairing_complete_cb;
2001 conn->disconn_cfm_cb = pairing_complete_cb;
2002 conn->io_capability = cp->io_cap;
2003 cmd->user_data = conn;
2004
2005 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002006 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002007 pairing_complete(cmd, 0);
2008
2009 err = 0;
2010
2011unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002012 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002013 return err;
2014}
2015
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002016static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2017 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002018{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002019 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002020 struct pending_cmd *cmd;
2021 struct hci_conn *conn;
2022 int err;
2023
2024 BT_DBG("");
2025
Johan Hedberg28424702012-02-02 04:02:29 +02002026 hci_dev_lock(hdev);
2027
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002028 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002029 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002030 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002031 goto unlock;
2032 }
2033
Johan Hedberg28424702012-02-02 04:02:29 +02002034 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2035 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002036 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002037 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002038 goto unlock;
2039 }
2040
2041 conn = cmd->user_data;
2042
2043 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002045 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002046 goto unlock;
2047 }
2048
2049 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002051 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002052 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002053unlock:
2054 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002055 return err;
2056}
2057
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002058static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002059 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2060 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002061{
Johan Hedberga5c29682011-02-19 12:05:57 -03002062 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002063 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002064 int err;
2065
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002066 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002067
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002068 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002069 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002070 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002071 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002072 }
2073
Andre Guedes591f47f2012-04-24 21:02:49 -03002074 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002075 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2076 else
Brian Gix47c15e22011-11-16 13:53:14 -08002077 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002078
Johan Hedberg272d90d2012-02-09 15:26:12 +02002079 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002080 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002081 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002082 goto done;
2083 }
2084
Andre Guedes591f47f2012-04-24 21:02:49 -03002085 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002086 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002087 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002088
Brian Gix5fe57d92011-12-21 16:12:13 -08002089 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002090 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002091 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002092 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002093 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002094 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002095
Brian Gix47c15e22011-11-16 13:53:14 -08002096 goto done;
2097 }
2098
Brian Gix0df4c182011-11-16 13:53:13 -08002099 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002100 if (!cmd) {
2101 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002102 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002103 }
2104
Brian Gix0df4c182011-11-16 13:53:13 -08002105 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002106 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2107 struct hci_cp_user_passkey_reply cp;
2108
2109 bacpy(&cp.bdaddr, bdaddr);
2110 cp.passkey = passkey;
2111 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2112 } else
2113 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2114
Johan Hedberga664b5b2011-02-19 12:06:02 -03002115 if (err < 0)
2116 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002117
Brian Gix0df4c182011-11-16 13:53:13 -08002118done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002119 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002120 return err;
2121}
2122
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302123static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2124 void *data, u16 len)
2125{
2126 struct mgmt_cp_pin_code_neg_reply *cp = data;
2127
2128 BT_DBG("");
2129
2130 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2131 MGMT_OP_PIN_CODE_NEG_REPLY,
2132 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2133}
2134
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002135static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2136 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002137{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002138 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002139
2140 BT_DBG("");
2141
2142 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002143 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002144 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002146 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002147 MGMT_OP_USER_CONFIRM_REPLY,
2148 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002149}
2150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002151static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002152 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002153{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002154 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002155
2156 BT_DBG("");
2157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002158 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002159 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2160 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002161}
2162
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002163static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2164 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002165{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002166 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002167
2168 BT_DBG("");
2169
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002170 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002171 MGMT_OP_USER_PASSKEY_REPLY,
2172 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002173}
2174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002175static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002177{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002178 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002179
2180 BT_DBG("");
2181
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002182 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002183 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2184 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002185}
2186
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002187static int update_name(struct hci_dev *hdev, const char *name)
2188{
2189 struct hci_cp_write_local_name cp;
2190
2191 memcpy(cp.name, name, sizeof(cp.name));
2192
2193 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2194}
2195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002196static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002197 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002198{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002199 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002200 struct pending_cmd *cmd;
2201 int err;
2202
2203 BT_DBG("");
2204
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002205 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002206
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002207 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002208
Johan Hedbergb5235a62012-02-21 14:32:24 +02002209 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002210 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002211
2212 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002213 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002214 if (err < 0)
2215 goto failed;
2216
2217 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002218 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002219
Johan Hedbergb5235a62012-02-21 14:32:24 +02002220 goto failed;
2221 }
2222
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002223 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002224 if (!cmd) {
2225 err = -ENOMEM;
2226 goto failed;
2227 }
2228
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002229 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002230 if (err < 0)
2231 mgmt_pending_remove(cmd);
2232
2233failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002234 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002235 return err;
2236}
2237
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002238static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002239 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002240{
Szymon Jancc35938b2011-03-22 13:12:21 +01002241 struct pending_cmd *cmd;
2242 int err;
2243
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002244 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002245
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002246 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002247
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002248 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002249 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002250 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002251 goto unlock;
2252 }
2253
Andre Guedes9a1a1992012-07-24 15:03:48 -03002254 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002255 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002256 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002257 goto unlock;
2258 }
2259
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002260 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002261 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002262 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002263 goto unlock;
2264 }
2265
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002266 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002267 if (!cmd) {
2268 err = -ENOMEM;
2269 goto unlock;
2270 }
2271
2272 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2273 if (err < 0)
2274 mgmt_pending_remove(cmd);
2275
2276unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002277 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002278 return err;
2279}
2280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002281static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002282 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002283{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002284 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002285 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002286 int err;
2287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002288 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002289
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002290 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002291
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002292 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002293 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002294 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002295 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002296 else
Szymon Janca6785be2012-12-13 15:11:21 +01002297 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002298
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002300 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002301
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002302 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002303 return err;
2304}
2305
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002306static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002307 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002308{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002309 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002310 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002311 int err;
2312
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002313 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002314
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002315 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002316
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002317 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002318 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002319 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002320 else
Szymon Janca6785be2012-12-13 15:11:21 +01002321 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002322
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002323 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002324 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002325
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002326 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002327 return err;
2328}
2329
Andre Guedes5e0452c2012-02-17 20:39:38 -03002330int mgmt_interleaved_discovery(struct hci_dev *hdev)
2331{
2332 int err;
2333
2334 BT_DBG("%s", hdev->name);
2335
2336 hci_dev_lock(hdev);
2337
2338 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2339 if (err < 0)
2340 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2341
2342 hci_dev_unlock(hdev);
2343
2344 return err;
2345}
2346
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002347static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002348 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002349{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002350 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002351 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002352 int err;
2353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002354 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002355
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002356 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002357
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002358 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002359 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002360 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002361 goto failed;
2362 }
2363
Andre Guedes642be6c2012-03-21 00:03:37 -03002364 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2365 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2366 MGMT_STATUS_BUSY);
2367 goto failed;
2368 }
2369
Johan Hedbergff9ef572012-01-04 14:23:45 +02002370 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002371 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002372 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002373 goto failed;
2374 }
2375
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002376 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002377 if (!cmd) {
2378 err = -ENOMEM;
2379 goto failed;
2380 }
2381
Andre Guedes4aab14e2012-02-17 20:39:36 -03002382 hdev->discovery.type = cp->type;
2383
2384 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002385 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002386 if (!lmp_bredr_capable(hdev)) {
2387 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2388 MGMT_STATUS_NOT_SUPPORTED);
2389 mgmt_pending_remove(cmd);
2390 goto failed;
2391 }
2392
2393 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002394 break;
2395
2396 case DISCOV_TYPE_LE:
Johan Hedberg04106752013-01-10 14:54:09 +02002397 if (!lmp_host_le_capable(hdev)) {
2398 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2399 MGMT_STATUS_NOT_SUPPORTED);
2400 mgmt_pending_remove(cmd);
2401 goto failed;
2402 }
2403
2404 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2405 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002406 break;
2407
Andre Guedes5e0452c2012-02-17 20:39:38 -03002408 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg04106752013-01-10 14:54:09 +02002409 if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) {
2410 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2411 MGMT_STATUS_NOT_SUPPORTED);
2412 mgmt_pending_remove(cmd);
2413 goto failed;
2414 }
2415
2416 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN,
2417 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002418 break;
2419
Andre Guedesf39799f2012-02-17 20:39:35 -03002420 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002421 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2422 MGMT_STATUS_INVALID_PARAMS);
2423 mgmt_pending_remove(cmd);
2424 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002425 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002426
Johan Hedberg14a53662011-04-27 10:29:56 -04002427 if (err < 0)
2428 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002429 else
2430 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002431
2432failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002433 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002434 return err;
2435}
2436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002437static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002438 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002439{
Johan Hedbergd9306502012-02-20 23:25:18 +02002440 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002441 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002442 struct hci_cp_remote_name_req_cancel cp;
2443 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002444 int err;
2445
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002446 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002447
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002448 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002449
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002450 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002451 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002452 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2453 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002454 goto unlock;
2455 }
2456
2457 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002458 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002459 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2460 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002461 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002462 }
2463
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002464 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002465 if (!cmd) {
2466 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002467 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002468 }
2469
Andre Guedese0d9727e2012-03-20 15:15:36 -03002470 switch (hdev->discovery.state) {
2471 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002472 if (test_bit(HCI_INQUIRY, &hdev->flags))
2473 err = hci_cancel_inquiry(hdev);
2474 else
2475 err = hci_cancel_le_scan(hdev);
2476
Andre Guedese0d9727e2012-03-20 15:15:36 -03002477 break;
2478
2479 case DISCOVERY_RESOLVING:
2480 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002481 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002482 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002483 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002484 err = cmd_complete(sk, hdev->id,
2485 MGMT_OP_STOP_DISCOVERY, 0,
2486 &mgmt_cp->type,
2487 sizeof(mgmt_cp->type));
2488 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2489 goto unlock;
2490 }
2491
2492 bacpy(&cp.bdaddr, &e->data.bdaddr);
2493 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2494 sizeof(cp), &cp);
2495
2496 break;
2497
2498 default:
2499 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2500 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002501 }
2502
Johan Hedberg14a53662011-04-27 10:29:56 -04002503 if (err < 0)
2504 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002505 else
2506 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002507
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002508unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002509 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002510 return err;
2511}
2512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002513static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002514 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002515{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002516 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002517 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002518 int err;
2519
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002520 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002521
Johan Hedberg561aafb2012-01-04 13:31:59 +02002522 hci_dev_lock(hdev);
2523
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002524 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002525 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002526 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002527 goto failed;
2528 }
2529
Johan Hedberga198e7b2012-02-17 14:27:06 +02002530 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002531 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002532 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002533 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002534 goto failed;
2535 }
2536
2537 if (cp->name_known) {
2538 e->name_state = NAME_KNOWN;
2539 list_del(&e->list);
2540 } else {
2541 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002542 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002543 }
2544
Johan Hedberge3846622013-01-09 15:29:33 +02002545 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
2546 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02002547
2548failed:
2549 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002550 return err;
2551}
2552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002553static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002554 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002555{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002556 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002557 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002558 int err;
2559
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002560 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002561
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002562 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002563
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002564 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002565 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002566 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002567 else
Szymon Janca6785be2012-12-13 15:11:21 +01002568 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002569
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002570 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002571 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002572
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002573 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002574
2575 return err;
2576}
2577
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002578static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002579 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002580{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002581 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002582 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002583 int err;
2584
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002585 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002586
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002587 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002588
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002589 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002590 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002591 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002592 else
Szymon Janca6785be2012-12-13 15:11:21 +01002593 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002595 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002596 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002597
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002598 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002599
2600 return err;
2601}
2602
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002603static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2604 u16 len)
2605{
2606 struct mgmt_cp_set_device_id *cp = data;
2607 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002608 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002609
2610 BT_DBG("%s", hdev->name);
2611
Szymon Jancc72d4b82012-03-16 16:02:57 +01002612 source = __le16_to_cpu(cp->source);
2613
2614 if (source > 0x0002)
2615 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2616 MGMT_STATUS_INVALID_PARAMS);
2617
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002618 hci_dev_lock(hdev);
2619
Szymon Jancc72d4b82012-03-16 16:02:57 +01002620 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002621 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2622 hdev->devid_product = __le16_to_cpu(cp->product);
2623 hdev->devid_version = __le16_to_cpu(cp->version);
2624
2625 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2626
2627 update_eir(hdev);
2628
2629 hci_dev_unlock(hdev);
2630
2631 return err;
2632}
2633
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002634static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002635 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002636{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002637 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002638 struct hci_cp_write_page_scan_activity acp;
2639 u8 type;
2640 int err;
2641
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002642 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002643
Johan Hedberg33c525c2012-10-24 21:11:58 +03002644 if (!lmp_bredr_capable(hdev))
2645 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2646 MGMT_STATUS_NOT_SUPPORTED);
2647
Johan Hedberga7e80f22013-01-09 16:05:19 +02002648 if (cp->val != 0x00 && cp->val != 0x01)
2649 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2650 MGMT_STATUS_INVALID_PARAMS);
2651
Johan Hedberg5400c042012-02-21 16:40:33 +02002652 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002653 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002654 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002655
2656 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002657 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002658 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002659
2660 hci_dev_lock(hdev);
2661
Johan Hedbergf7c6869c2011-12-15 00:47:36 +02002662 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002663 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002664
Johan Hedberg83ce9a062012-06-28 13:44:30 +03002665 /* 160 msec page scan interval */
2666 acp.interval = __constant_cpu_to_le16(0x0100);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002667 } else {
2668 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002669
2670 /* default 1.28 sec page scan */
2671 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002672 }
2673
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002674 /* default 11.25 msec page scan window */
2675 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002676
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002677 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2678 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002679 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002680 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002681 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002682 goto done;
2683 }
2684
2685 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2686 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002687 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002688 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002689 goto done;
2690 }
2691
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002692 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002693 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002694done:
2695 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002696 return err;
2697}
2698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002699static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002701{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002702 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2703 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002704 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002705
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002706 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002707
2708 expected_len = sizeof(*cp) + key_count *
2709 sizeof(struct mgmt_ltk_info);
2710 if (expected_len != len) {
2711 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002712 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002713 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002714 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002715 }
2716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002717 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002718
2719 hci_dev_lock(hdev);
2720
2721 hci_smp_ltks_clear(hdev);
2722
2723 for (i = 0; i < key_count; i++) {
2724 struct mgmt_ltk_info *key = &cp->keys[i];
2725 u8 type;
2726
2727 if (key->master)
2728 type = HCI_SMP_LTK;
2729 else
2730 type = HCI_SMP_LTK_SLAVE;
2731
Hemant Gupta4596fde52012-04-16 14:57:40 +05302732 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002733 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002734 type, 0, key->authenticated, key->val,
2735 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002736 }
2737
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002738 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
2739 NULL, 0);
2740
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002741 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002742
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002743 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002744}
2745
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002746static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2748 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002749 bool var_len;
2750 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002751} mgmt_handlers[] = {
2752 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002753 { read_version, false, MGMT_READ_VERSION_SIZE },
2754 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2755 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2756 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2757 { set_powered, false, MGMT_SETTING_SIZE },
2758 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2759 { set_connectable, false, MGMT_SETTING_SIZE },
2760 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2761 { set_pairable, false, MGMT_SETTING_SIZE },
2762 { set_link_security, false, MGMT_SETTING_SIZE },
2763 { set_ssp, false, MGMT_SETTING_SIZE },
2764 { set_hs, false, MGMT_SETTING_SIZE },
2765 { set_le, false, MGMT_SETTING_SIZE },
2766 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2767 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2768 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2769 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2770 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2771 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2772 { disconnect, false, MGMT_DISCONNECT_SIZE },
2773 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2774 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2775 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2776 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2777 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2778 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2779 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2780 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2781 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2782 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2783 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2784 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2785 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2786 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2787 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2788 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2789 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2790 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2791 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002792 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002793};
2794
2795
Johan Hedberg03811012010-12-08 00:21:06 +02002796int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002798 void *buf;
2799 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002800 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002801 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002803 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002804 int err;
2805
2806 BT_DBG("got %zu bytes", msglen);
2807
2808 if (msglen < sizeof(*hdr))
2809 return -EINVAL;
2810
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002811 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002812 if (!buf)
2813 return -ENOMEM;
2814
2815 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2816 err = -EFAULT;
2817 goto done;
2818 }
2819
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002820 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002821 opcode = __le16_to_cpu(hdr->opcode);
2822 index = __le16_to_cpu(hdr->index);
2823 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002824
2825 if (len != msglen - sizeof(*hdr)) {
2826 err = -EINVAL;
2827 goto done;
2828 }
2829
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002830 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002831 hdev = hci_dev_get(index);
2832 if (!hdev) {
2833 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002834 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002835 goto done;
2836 }
2837 }
2838
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002839 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002840 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002841 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002842 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002843 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002844 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002845 }
2846
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002847 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002848 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002849 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002850 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002851 goto done;
2852 }
2853
Johan Hedbergbe22b542012-03-01 22:24:41 +02002854 handler = &mgmt_handlers[opcode];
2855
2856 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002857 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002858 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002859 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002860 goto done;
2861 }
2862
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002863 if (hdev)
2864 mgmt_init_hdev(sk, hdev);
2865
2866 cp = buf + sizeof(*hdr);
2867
Johan Hedbergbe22b542012-03-01 22:24:41 +02002868 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002869 if (err < 0)
2870 goto done;
2871
Johan Hedberg03811012010-12-08 00:21:06 +02002872 err = msglen;
2873
2874done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002875 if (hdev)
2876 hci_dev_put(hdev);
2877
Johan Hedberg03811012010-12-08 00:21:06 +02002878 kfree(buf);
2879 return err;
2880}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002881
Johan Hedbergb24752f2011-11-03 14:40:33 +02002882static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2883{
2884 u8 *status = data;
2885
2886 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2887 mgmt_pending_remove(cmd);
2888}
2889
Johan Hedberg744cf192011-11-08 20:40:14 +02002890int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002891{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002892 if (!mgmt_valid_hdev(hdev))
2893 return -ENOTSUPP;
2894
Johan Hedberg744cf192011-11-08 20:40:14 +02002895 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002896}
2897
Johan Hedberg744cf192011-11-08 20:40:14 +02002898int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002899{
Johan Hedberg5f159032012-03-02 03:13:19 +02002900 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002901
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002902 if (!mgmt_valid_hdev(hdev))
2903 return -ENOTSUPP;
2904
Johan Hedberg744cf192011-11-08 20:40:14 +02002905 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002906
Johan Hedberg744cf192011-11-08 20:40:14 +02002907 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002908}
2909
Johan Hedberg73f22f62010-12-29 16:00:25 +02002910struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002911 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002912 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002913 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002914};
2915
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002916static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002917{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002918 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002919
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002920 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002921
2922 list_del(&cmd->list);
2923
2924 if (match->sk == NULL) {
2925 match->sk = cmd->sk;
2926 sock_hold(match->sk);
2927 }
2928
2929 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002930}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002931
Johan Hedberg7f0ae642012-10-24 21:11:57 +03002932static int set_bredr_scan(struct hci_dev *hdev)
2933{
2934 u8 scan = 0;
2935
2936 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2937 scan |= SCAN_PAGE;
2938 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2939 scan |= SCAN_INQUIRY;
2940
2941 if (!scan)
2942 return 0;
2943
2944 return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2945}
2946
Johan Hedberg744cf192011-11-08 20:40:14 +02002947int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002948{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002949 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002950 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002951
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002952 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2953 return 0;
2954
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002955 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002956
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002957 if (powered) {
Johan Hedberg6b4b73e2012-10-25 00:09:52 +03002958 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
2959 !lmp_host_ssp_capable(hdev)) {
Andrzej Kaczmarek3d1cbdd2012-08-29 10:02:08 +02002960 u8 ssp = 1;
2961
2962 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
2963 }
2964
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02002965 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
2966 struct hci_cp_write_le_host_supported cp;
2967
2968 cp.le = 1;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002969 cp.simul = lmp_le_br_capable(hdev);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02002970
Johan Hedberg430a61b2012-10-25 00:09:53 +03002971 /* Check first if we already have the right
2972 * host state (host features set)
2973 */
Gustavo Padovanffa88e02012-11-23 16:50:51 -02002974 if (cp.le != lmp_host_le_capable(hdev) ||
2975 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg430a61b2012-10-25 00:09:53 +03002976 hci_send_cmd(hdev,
2977 HCI_OP_WRITE_LE_HOST_SUPPORTED,
2978 sizeof(cp), &cp);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02002979 }
2980
Johan Hedberg7f0ae642012-10-24 21:11:57 +03002981 if (lmp_bredr_capable(hdev)) {
2982 set_bredr_scan(hdev);
2983 update_class(hdev);
2984 update_name(hdev, hdev->dev_name);
2985 update_eir(hdev);
2986 }
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002987 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002988 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002989 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002990 }
2991
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002992 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002993
2994 if (match.sk)
2995 sock_put(match.sk);
2996
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002997 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002998}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002999
Johan Hedberg744cf192011-11-08 20:40:14 +02003000int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003001{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003002 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003003 bool changed = false;
3004 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003005
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003006 if (discoverable) {
3007 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3008 changed = true;
3009 } else {
3010 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3011 changed = true;
3012 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003013
Johan Hedberged9b5f22012-02-21 20:47:06 +02003014 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003015 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003016
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003017 if (changed)
3018 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003019
Johan Hedberg73f22f62010-12-29 16:00:25 +02003020 if (match.sk)
3021 sock_put(match.sk);
3022
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003023 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003024}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003025
Johan Hedberg744cf192011-11-08 20:40:14 +02003026int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003027{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003028 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003029 bool changed = false;
3030 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003031
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003032 if (connectable) {
3033 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3034 changed = true;
3035 } else {
3036 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3037 changed = true;
3038 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003039
Johan Hedberged9b5f22012-02-21 20:47:06 +02003040 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003041 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003042
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003043 if (changed)
3044 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003045
3046 if (match.sk)
3047 sock_put(match.sk);
3048
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003049 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003050}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003051
Johan Hedberg744cf192011-11-08 20:40:14 +02003052int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003053{
Johan Hedbergca69b792011-11-11 18:10:00 +02003054 u8 mgmt_err = mgmt_status(status);
3055
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003056 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003057 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003058 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003059
3060 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003061 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003062 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003063
3064 return 0;
3065}
3066
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003067int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3068 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003069{
Johan Hedberg86742e12011-11-07 23:13:38 +02003070 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003071
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003072 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003073
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003074 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003075 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003076 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003077 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003078 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003079 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003080
Johan Hedberg744cf192011-11-08 20:40:14 +02003081 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003082}
Johan Hedbergf7520542011-01-20 12:34:39 +02003083
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003084int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3085{
3086 struct mgmt_ev_new_long_term_key ev;
3087
3088 memset(&ev, 0, sizeof(ev));
3089
3090 ev.store_hint = persistent;
3091 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003092 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003093 ev.key.authenticated = key->authenticated;
3094 ev.key.enc_size = key->enc_size;
3095 ev.key.ediv = key->ediv;
3096
3097 if (key->type == HCI_SMP_LTK)
3098 ev.key.master = 1;
3099
3100 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3101 memcpy(ev.key.val, key->val, sizeof(key->val));
3102
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003103 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3104 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003105}
3106
Johan Hedbergafc747a2012-01-15 18:11:07 +02003107int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003108 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3109 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003110{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003111 char buf[512];
3112 struct mgmt_ev_device_connected *ev = (void *) buf;
3113 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003114
Johan Hedbergb644ba32012-01-17 21:48:47 +02003115 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003116 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003117
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003118 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003119
Johan Hedbergb644ba32012-01-17 21:48:47 +02003120 if (name_len > 0)
3121 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003122 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003123
3124 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003125 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003126 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003127
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003128 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003129
3130 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003131 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003132}
3133
Johan Hedberg8962ee72011-01-20 12:40:27 +02003134static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3135{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003136 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003137 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003138 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003139
Johan Hedberg88c3df12012-02-09 14:27:38 +02003140 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3141 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003142
Johan Hedbergaee9b212012-02-18 15:07:59 +02003143 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003144 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003145
3146 *sk = cmd->sk;
3147 sock_hold(*sk);
3148
Johan Hedberga664b5b2011-02-19 12:06:02 -03003149 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003150}
3151
Johan Hedberg124f6e32012-02-09 13:50:12 +02003152static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003153{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003154 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003155 struct mgmt_cp_unpair_device *cp = cmd->param;
3156 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003157
3158 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003159 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3160 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003161
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003162 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3163
Johan Hedbergaee9b212012-02-18 15:07:59 +02003164 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003165
3166 mgmt_pending_remove(cmd);
3167}
3168
Johan Hedbergafc747a2012-01-15 18:11:07 +02003169int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003170 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003171{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003172 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003173 struct sock *sk = NULL;
3174 int err;
3175
Johan Hedberg744cf192011-11-08 20:40:14 +02003176 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003177
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003178 bacpy(&ev.addr.bdaddr, bdaddr);
3179 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3180 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003181
Johan Hedbergafc747a2012-01-15 18:11:07 +02003182 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003183 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003184
3185 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003186 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003187
Johan Hedberg124f6e32012-02-09 13:50:12 +02003188 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003189 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003190
Johan Hedberg8962ee72011-01-20 12:40:27 +02003191 return err;
3192}
3193
Johan Hedberg88c3df12012-02-09 14:27:38 +02003194int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003195 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003196{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003197 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003198 struct pending_cmd *cmd;
3199 int err;
3200
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003201 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3202 hdev);
3203
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003204 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003205 if (!cmd)
3206 return -ENOENT;
3207
Johan Hedberg88c3df12012-02-09 14:27:38 +02003208 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003209 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003210
Johan Hedberg88c3df12012-02-09 14:27:38 +02003211 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003212 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003213
Johan Hedberga664b5b2011-02-19 12:06:02 -03003214 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003215
3216 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003217}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003218
Johan Hedberg48264f02011-11-09 13:58:58 +02003219int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003220 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003221{
3222 struct mgmt_ev_connect_failed ev;
3223
Johan Hedberg4c659c32011-11-07 23:13:39 +02003224 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003225 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003226 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003227
Johan Hedberg744cf192011-11-08 20:40:14 +02003228 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003229}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003230
Johan Hedberg744cf192011-11-08 20:40:14 +02003231int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003232{
3233 struct mgmt_ev_pin_code_request ev;
3234
Johan Hedbergd8457692012-02-17 14:24:57 +02003235 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003236 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003237 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003238
Johan Hedberg744cf192011-11-08 20:40:14 +02003239 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003240 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003241}
3242
Johan Hedberg744cf192011-11-08 20:40:14 +02003243int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003244 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003245{
3246 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003247 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003248 int err;
3249
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003250 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003251 if (!cmd)
3252 return -ENOENT;
3253
Johan Hedbergd8457692012-02-17 14:24:57 +02003254 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003255 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003256
Johan Hedbergaee9b212012-02-18 15:07:59 +02003257 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003258 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003259
Johan Hedberga664b5b2011-02-19 12:06:02 -03003260 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003261
3262 return err;
3263}
3264
Johan Hedberg744cf192011-11-08 20:40:14 +02003265int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003266 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003267{
3268 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003269 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003270 int err;
3271
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003272 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003273 if (!cmd)
3274 return -ENOENT;
3275
Johan Hedbergd8457692012-02-17 14:24:57 +02003276 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003277 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003278
Johan Hedbergaee9b212012-02-18 15:07:59 +02003279 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003280 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003281
Johan Hedberga664b5b2011-02-19 12:06:02 -03003282 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003283
3284 return err;
3285}
Johan Hedberga5c29682011-02-19 12:05:57 -03003286
Johan Hedberg744cf192011-11-08 20:40:14 +02003287int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003288 u8 link_type, u8 addr_type, __le32 value,
3289 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003290{
3291 struct mgmt_ev_user_confirm_request ev;
3292
Johan Hedberg744cf192011-11-08 20:40:14 +02003293 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003294
Johan Hedberg272d90d2012-02-09 15:26:12 +02003295 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003296 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003297 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003298 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003299
Johan Hedberg744cf192011-11-08 20:40:14 +02003300 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003301 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003302}
3303
Johan Hedberg272d90d2012-02-09 15:26:12 +02003304int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003305 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003306{
3307 struct mgmt_ev_user_passkey_request ev;
3308
3309 BT_DBG("%s", hdev->name);
3310
Johan Hedberg272d90d2012-02-09 15:26:12 +02003311 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003312 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003313
3314 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003315 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003316}
3317
Brian Gix0df4c182011-11-16 13:53:13 -08003318static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003319 u8 link_type, u8 addr_type, u8 status,
3320 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003321{
3322 struct pending_cmd *cmd;
3323 struct mgmt_rp_user_confirm_reply rp;
3324 int err;
3325
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003326 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003327 if (!cmd)
3328 return -ENOENT;
3329
Johan Hedberg272d90d2012-02-09 15:26:12 +02003330 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003331 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003332 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003333 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003334
Johan Hedberga664b5b2011-02-19 12:06:02 -03003335 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003336
3337 return err;
3338}
3339
Johan Hedberg744cf192011-11-08 20:40:14 +02003340int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003341 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003342{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003343 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003344 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003345}
3346
Johan Hedberg272d90d2012-02-09 15:26:12 +02003347int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003348 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003349{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003350 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003351 status,
3352 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003353}
Johan Hedberg2a611692011-02-19 12:06:00 -03003354
Brian Gix604086b2011-11-23 08:28:33 -08003355int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003356 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003357{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003358 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003359 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003360}
3361
Johan Hedberg272d90d2012-02-09 15:26:12 +02003362int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003363 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003364{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003365 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003366 status,
3367 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003368}
3369
Johan Hedberg92a25252012-09-06 18:39:26 +03003370int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3371 u8 link_type, u8 addr_type, u32 passkey,
3372 u8 entered)
3373{
3374 struct mgmt_ev_passkey_notify ev;
3375
3376 BT_DBG("%s", hdev->name);
3377
3378 bacpy(&ev.addr.bdaddr, bdaddr);
3379 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3380 ev.passkey = __cpu_to_le32(passkey);
3381 ev.entered = entered;
3382
3383 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3384}
3385
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003386int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003387 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003388{
3389 struct mgmt_ev_auth_failed ev;
3390
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003391 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003392 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003393 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003394
Johan Hedberg744cf192011-11-08 20:40:14 +02003395 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003396}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003397
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003398int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3399{
3400 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003401 bool changed = false;
3402 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003403
3404 if (status) {
3405 u8 mgmt_err = mgmt_status(status);
3406 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003407 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003408 return 0;
3409 }
3410
Johan Hedberg47990ea2012-02-22 11:58:37 +02003411 if (test_bit(HCI_AUTH, &hdev->flags)) {
3412 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3413 changed = true;
3414 } else {
3415 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3416 changed = true;
3417 }
3418
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003419 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003420 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003421
Johan Hedberg47990ea2012-02-22 11:58:37 +02003422 if (changed)
3423 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003424
3425 if (match.sk)
3426 sock_put(match.sk);
3427
3428 return err;
3429}
3430
Johan Hedbergcacaf522012-02-21 00:52:42 +02003431static int clear_eir(struct hci_dev *hdev)
3432{
3433 struct hci_cp_write_eir cp;
3434
Johan Hedberg976eb202012-10-24 21:12:01 +03003435 if (!lmp_ext_inq_capable(hdev))
Johan Hedbergcacaf522012-02-21 00:52:42 +02003436 return 0;
3437
Johan Hedbergc80da272012-02-22 15:38:48 +02003438 memset(hdev->eir, 0, sizeof(hdev->eir));
3439
Johan Hedbergcacaf522012-02-21 00:52:42 +02003440 memset(&cp, 0, sizeof(cp));
3441
3442 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3443}
3444
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003445int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003446{
3447 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003448 bool changed = false;
3449 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003450
3451 if (status) {
3452 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003453
3454 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003455 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003456 err = new_settings(hdev, NULL);
3457
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003458 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3459 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003460
3461 return err;
3462 }
3463
3464 if (enable) {
3465 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3466 changed = true;
3467 } else {
3468 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3469 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003470 }
3471
3472 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3473
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003474 if (changed)
3475 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003476
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003477 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003478 sock_put(match.sk);
3479
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003480 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3481 update_eir(hdev);
3482 else
3483 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003484
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003485 return err;
3486}
3487
Johan Hedberg90e70452012-02-23 23:09:40 +02003488static void class_rsp(struct pending_cmd *cmd, void *data)
3489{
3490 struct cmd_lookup *match = data;
3491
3492 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003493 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003494
3495 list_del(&cmd->list);
3496
3497 if (match->sk == NULL) {
3498 match->sk = cmd->sk;
3499 sock_hold(match->sk);
3500 }
3501
3502 mgmt_pending_free(cmd);
3503}
3504
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003505int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003506 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003507{
Johan Hedberg90e70452012-02-23 23:09:40 +02003508 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3509 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003510
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003511 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3512
Johan Hedberg90e70452012-02-23 23:09:40 +02003513 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3514 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3515 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3516
3517 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003518 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3519 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003520
3521 if (match.sk)
3522 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003523
3524 return err;
3525}
3526
Johan Hedberg744cf192011-11-08 20:40:14 +02003527int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003528{
3529 struct pending_cmd *cmd;
3530 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003531 bool changed = false;
3532 int err = 0;
3533
3534 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3535 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3536 changed = true;
3537 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003538
3539 memset(&ev, 0, sizeof(ev));
3540 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003541 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003542
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003543 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003544 if (!cmd)
3545 goto send_event;
3546
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003547 /* Always assume that either the short or the complete name has
3548 * changed if there was a pending mgmt command */
3549 changed = true;
3550
Johan Hedbergb312b1612011-03-16 14:29:37 +02003551 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003552 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003553 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003554 goto failed;
3555 }
3556
Johan Hedbergaee9b212012-02-18 15:07:59 +02003557 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003558 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003559 if (err < 0)
3560 goto failed;
3561
3562send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003563 if (changed)
3564 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003565 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003566
Johan Hedberg1225a6b2012-10-25 00:09:54 +03003567 /* EIR is taken care of separately when powering on the
3568 * adapter so only update them here if this is a name change
3569 * unrelated to power on.
3570 */
3571 if (!test_bit(HCI_INIT, &hdev->flags))
3572 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003573
3574failed:
3575 if (cmd)
3576 mgmt_pending_remove(cmd);
3577 return err;
3578}
Szymon Jancc35938b2011-03-22 13:12:21 +01003579
Johan Hedberg744cf192011-11-08 20:40:14 +02003580int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003581 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003582{
3583 struct pending_cmd *cmd;
3584 int err;
3585
Johan Hedberg744cf192011-11-08 20:40:14 +02003586 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003587
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003588 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003589 if (!cmd)
3590 return -ENOENT;
3591
3592 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003593 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3594 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003595 } else {
3596 struct mgmt_rp_read_local_oob_data rp;
3597
3598 memcpy(rp.hash, hash, sizeof(rp.hash));
3599 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3600
Johan Hedberg744cf192011-11-08 20:40:14 +02003601 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003602 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3603 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003604 }
3605
3606 mgmt_pending_remove(cmd);
3607
3608 return err;
3609}
Johan Hedberge17acd42011-03-30 23:57:16 +03003610
Johan Hedberg06199cf2012-02-22 16:37:11 +02003611int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3612{
3613 struct cmd_lookup match = { NULL, hdev };
3614 bool changed = false;
3615 int err = 0;
3616
3617 if (status) {
3618 u8 mgmt_err = mgmt_status(status);
3619
3620 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003621 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003622 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003623
Szymon Jancd97dcb62012-03-16 16:02:56 +01003624 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3625 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003626
3627 return err;
3628 }
3629
3630 if (enable) {
3631 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3632 changed = true;
3633 } else {
3634 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3635 changed = true;
3636 }
3637
3638 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3639
3640 if (changed)
3641 err = new_settings(hdev, match.sk);
3642
3643 if (match.sk)
3644 sock_put(match.sk);
3645
3646 return err;
3647}
3648
Johan Hedberg48264f02011-11-09 13:58:58 +02003649int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003650 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3651 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003652{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003653 char buf[512];
3654 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003655 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003656
Johan Hedberg1dc06092012-01-15 21:01:23 +02003657 /* Leave 5 bytes for a potential CoD field */
3658 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003659 return -EINVAL;
3660
Johan Hedberg1dc06092012-01-15 21:01:23 +02003661 memset(buf, 0, sizeof(buf));
3662
Johan Hedberge319d2e2012-01-15 19:51:59 +02003663 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003664 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003665 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003666 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303667 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003668 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303669 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003670
Johan Hedberg1dc06092012-01-15 21:01:23 +02003671 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003672 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003673
Johan Hedberg1dc06092012-01-15 21:01:23 +02003674 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3675 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003676 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003677
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003678 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003679 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003680
Johan Hedberge319d2e2012-01-15 19:51:59 +02003681 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003682}
Johan Hedberga88a9652011-03-30 13:18:12 +03003683
Johan Hedbergb644ba32012-01-17 21:48:47 +02003684int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003685 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003686{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003687 struct mgmt_ev_device_found *ev;
3688 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3689 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003690
Johan Hedbergb644ba32012-01-17 21:48:47 +02003691 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003692
Johan Hedbergb644ba32012-01-17 21:48:47 +02003693 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003694
Johan Hedbergb644ba32012-01-17 21:48:47 +02003695 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003696 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003697 ev->rssi = rssi;
3698
3699 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003700 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003701
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003702 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003703
Johan Hedberg053c7e02012-02-04 00:06:00 +02003704 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003705 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003706}
Johan Hedberg314b2382011-04-27 10:29:57 -04003707
Andre Guedes7a135102011-11-09 17:14:25 -03003708int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003709{
3710 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003711 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003712 int err;
3713
Andre Guedes203159d2012-02-13 15:41:01 -03003714 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3715
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003716 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003717 if (!cmd)
3718 return -ENOENT;
3719
Johan Hedbergf808e162012-02-19 12:52:07 +02003720 type = hdev->discovery.type;
3721
3722 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003723 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003724 mgmt_pending_remove(cmd);
3725
3726 return err;
3727}
3728
Andre Guedese6d465c2011-11-09 17:14:26 -03003729int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3730{
3731 struct pending_cmd *cmd;
3732 int err;
3733
3734 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3735 if (!cmd)
3736 return -ENOENT;
3737
Johan Hedbergd9306502012-02-20 23:25:18 +02003738 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003739 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003740 mgmt_pending_remove(cmd);
3741
3742 return err;
3743}
Johan Hedberg314b2382011-04-27 10:29:57 -04003744
Johan Hedberg744cf192011-11-08 20:40:14 +02003745int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003746{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003747 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003748 struct pending_cmd *cmd;
3749
Andre Guedes343fb142011-11-22 17:14:19 -03003750 BT_DBG("%s discovering %u", hdev->name, discovering);
3751
Johan Hedberg164a6e72011-11-01 17:06:44 +02003752 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003753 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003754 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003755 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003756
3757 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003758 u8 type = hdev->discovery.type;
3759
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003760 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3761 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003762 mgmt_pending_remove(cmd);
3763 }
3764
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003765 memset(&ev, 0, sizeof(ev));
3766 ev.type = hdev->discovery.type;
3767 ev.discovering = discovering;
3768
3769 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003770}
Antti Julku5e762442011-08-25 16:48:02 +03003771
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003772int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003773{
3774 struct pending_cmd *cmd;
3775 struct mgmt_ev_device_blocked ev;
3776
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003777 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003778
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003779 bacpy(&ev.addr.bdaddr, bdaddr);
3780 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003781
Johan Hedberg744cf192011-11-08 20:40:14 +02003782 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003783 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003784}
3785
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003786int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003787{
3788 struct pending_cmd *cmd;
3789 struct mgmt_ev_device_unblocked ev;
3790
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003791 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003792
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003793 bacpy(&ev.addr.bdaddr, bdaddr);
3794 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003795
Johan Hedberg744cf192011-11-08 20:40:14 +02003796 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003797 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003798}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003799
3800module_param(enable_hs, bool, 0644);
3801MODULE_PARM_DESC(enable_hs, "Enable High Speed support");