blob: dedbb1d8b2d252800637975d720b937bcb029b53 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg23b3b132012-09-06 18:39:27 +030038#define MGMT_REVISION 2
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Andre Guedes3fd24152012-02-03 17:48:01 -0300105/*
106 * These LE scan and inquiry parameters were chosen according to LE General
107 * Discovery Procedure specification.
108 */
109#define LE_SCAN_TYPE 0x01
110#define LE_SCAN_WIN 0x12
111#define LE_SCAN_INT 0x12
112#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300113#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300114
Andre Guedese8777522012-02-03 17:48:02 -0300115#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300116#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300117
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800118#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200119
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200120#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
121 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
122
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200123struct pending_cmd {
124 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200125 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200126 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100127 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200128 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300129 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200130};
131
Johan Hedbergca69b792011-11-11 18:10:00 +0200132/* HCI to MGMT error code conversion table */
133static u8 mgmt_status_table[] = {
134 MGMT_STATUS_SUCCESS,
135 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
136 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
137 MGMT_STATUS_FAILED, /* Hardware Failure */
138 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
139 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
140 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
141 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
142 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
143 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
145 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
146 MGMT_STATUS_BUSY, /* Command Disallowed */
147 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
148 MGMT_STATUS_REJECTED, /* Rejected Security */
149 MGMT_STATUS_REJECTED, /* Rejected Personal */
150 MGMT_STATUS_TIMEOUT, /* Host Timeout */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
153 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
154 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
155 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
156 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
157 MGMT_STATUS_BUSY, /* Repeated Attempts */
158 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
159 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
160 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
161 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
162 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
163 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
164 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
165 MGMT_STATUS_FAILED, /* Unspecified Error */
166 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
167 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
168 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
169 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
170 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
171 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
172 MGMT_STATUS_FAILED, /* Unit Link Key Used */
173 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
174 MGMT_STATUS_TIMEOUT, /* Instant Passed */
175 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
176 MGMT_STATUS_FAILED, /* Transaction Collision */
177 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
178 MGMT_STATUS_REJECTED, /* QoS Rejected */
179 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
180 MGMT_STATUS_REJECTED, /* Insufficient Security */
181 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
182 MGMT_STATUS_BUSY, /* Role Switch Pending */
183 MGMT_STATUS_FAILED, /* Slot Violation */
184 MGMT_STATUS_FAILED, /* Role Switch Failed */
185 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
186 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
187 MGMT_STATUS_BUSY, /* Host Busy Pairing */
188 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
189 MGMT_STATUS_BUSY, /* Controller Busy */
190 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
191 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
192 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
193 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
194 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
195};
196
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300197bool mgmt_valid_hdev(struct hci_dev *hdev)
198{
199 return hdev->dev_type == HCI_BREDR;
200}
201
Johan Hedbergca69b792011-11-11 18:10:00 +0200202static u8 mgmt_status(u8 hci_status)
203{
204 if (hci_status < ARRAY_SIZE(mgmt_status_table))
205 return mgmt_status_table[hci_status];
206
207 return MGMT_STATUS_FAILED;
208}
209
Szymon Janc4e51eae2011-02-25 19:05:48 +0100210static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200211{
212 struct sk_buff *skb;
213 struct mgmt_hdr *hdr;
214 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300215 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200216
Szymon Janc34eb5252011-02-28 14:10:08 +0100217 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200218
Andre Guedes790eff42012-06-07 19:05:46 -0300219 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220 if (!skb)
221 return -ENOMEM;
222
223 hdr = (void *) skb_put(skb, sizeof(*hdr));
224
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 Hedbergf7b64e62010-12-13 21:07:06 +0200227 hdr->len = cpu_to_le16(sizeof(*ev));
228
229 ev = (void *) skb_put(skb, sizeof(*ev));
230 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200231 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 err = sock_queue_rcv_skb(sk, skb);
234 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200235 kfree_skb(skb);
236
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300237 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200238}
239
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200240static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300241 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200242{
243 struct sk_buff *skb;
244 struct mgmt_hdr *hdr;
245 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300246 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
248 BT_DBG("sock %p", sk);
249
Andre Guedes790eff42012-06-07 19:05:46 -0300250 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251 if (!skb)
252 return -ENOMEM;
253
254 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200255
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 Hedbergaee9b2182012-02-18 15:07:59 +0200262 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100263
264 if (rp)
265 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200266
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 err = sock_queue_rcv_skb(sk, skb);
268 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200269 kfree_skb(skb);
270
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100271 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200272}
273
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
275 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200276{
277 struct mgmt_rp_read_version rp;
278
279 BT_DBG("sock %p", sk);
280
281 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200282 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200283
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200284 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200286}
287
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300288static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
289 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200290{
291 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200292 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
293 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200294 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295 size_t rp_size;
296 int i, err;
297
298 BT_DBG("sock %p", sk);
299
300 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
301
302 rp = kmalloc(rp_size, GFP_KERNEL);
303 if (!rp)
304 return -ENOMEM;
305
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200306 rp->num_commands = __constant_cpu_to_le16(num_commands);
307 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200308
309 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
310 put_unaligned_le16(mgmt_commands[i], opcode);
311
312 for (i = 0; i < num_events; i++, opcode++)
313 put_unaligned_le16(mgmt_events[i], opcode);
314
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200315 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300316 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200317 kfree(rp);
318
319 return err;
320}
321
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300322static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
323 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200326 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200329 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330
331 BT_DBG("sock %p", sk);
332
333 read_lock(&hci_dev_list_lock);
334
335 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300336 list_for_each_entry(d, &hci_dev_list, list) {
337 if (!mgmt_valid_hdev(d))
338 continue;
339
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340 count++;
341 }
342
Johan Hedberga38528f2011-01-22 06:46:43 +0200343 rp_len = sizeof(*rp) + (2 * count);
344 rp = kmalloc(rp_len, GFP_ATOMIC);
345 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100346 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200347 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100348 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200350 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200351
352 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200353 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200354 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200355 continue;
356
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300357 if (!mgmt_valid_hdev(d))
358 continue;
359
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200360 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200361 BT_DBG("Added hci%u", d->id);
362 }
363
364 read_unlock(&hci_dev_list_lock);
365
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200366 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300367 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200368
Johan Hedberga38528f2011-01-22 06:46:43 +0200369 kfree(rp);
370
371 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200372}
373
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200375{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200380
Andre Guedes9a1a1992012-07-24 15:03:48 -0300381 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200382 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200383
Andre Guedesed3fa312012-07-24 15:03:46 -0300384 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300385 settings |= MGMT_SETTING_CONNECTABLE;
386 settings |= MGMT_SETTING_FAST_CONNECTABLE;
387 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 settings |= MGMT_SETTING_BREDR;
389 settings |= MGMT_SETTING_LINK_SECURITY;
390 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200391
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100392 if (enable_hs)
393 settings |= MGMT_SETTING_HS;
394
Andre Guedesc383ddc2012-07-24 15:03:47 -0300395 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200396 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200397
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200398 return settings;
399}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200400
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401static u32 get_current_settings(struct hci_dev *hdev)
402{
403 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200404
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200405 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100406 settings |= MGMT_SETTING_POWERED;
407
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200408 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_CONNECTABLE;
410
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200411 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_DISCOVERABLE;
413
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200414 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_PAIRABLE;
416
Andre Guedesed3fa312012-07-24 15:03:46 -0300417 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_BREDR;
419
Johan Hedberg06199cf2012-02-22 16:37:11 +0200420 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200422
Johan Hedberg47990ea2012-02-22 11:58:37 +0200423 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200424 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200425
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200426 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200427 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200428
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200429 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
430 settings |= MGMT_SETTING_HS;
431
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200432 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200433}
434
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300435#define PNP_INFO_SVCLASS_ID 0x1200
436
437static u8 bluetooth_base_uuid[] = {
438 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
439 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
440};
441
442static u16 get_uuid16(u8 *uuid128)
443{
444 u32 val;
445 int i;
446
447 for (i = 0; i < 12; i++) {
448 if (bluetooth_base_uuid[i] != uuid128[i])
449 return 0;
450 }
451
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200452 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300453 if (val > 0xffff)
454 return 0;
455
456 return (u16) val;
457}
458
459static void create_eir(struct hci_dev *hdev, u8 *data)
460{
461 u8 *ptr = data;
462 u16 eir_len = 0;
463 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
464 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200465 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300466 size_t name_len;
467
468 name_len = strlen(hdev->dev_name);
469
470 if (name_len > 0) {
471 /* EIR Data type */
472 if (name_len > 48) {
473 name_len = 48;
474 ptr[1] = EIR_NAME_SHORT;
475 } else
476 ptr[1] = EIR_NAME_COMPLETE;
477
478 /* EIR Data length */
479 ptr[0] = name_len + 1;
480
481 memcpy(ptr + 2, hdev->dev_name, name_len);
482
483 eir_len += (name_len + 2);
484 ptr += (name_len + 2);
485 }
486
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100487 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700488 ptr[0] = 2;
489 ptr[1] = EIR_TX_POWER;
490 ptr[2] = (u8) hdev->inq_tx_power;
491
492 eir_len += 3;
493 ptr += 3;
494 }
495
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700496 if (hdev->devid_source > 0) {
497 ptr[0] = 9;
498 ptr[1] = EIR_DEVICE_ID;
499
500 put_unaligned_le16(hdev->devid_source, ptr + 2);
501 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
502 put_unaligned_le16(hdev->devid_product, ptr + 6);
503 put_unaligned_le16(hdev->devid_version, ptr + 8);
504
505 eir_len += 10;
506 ptr += 10;
507 }
508
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300509 memset(uuid16_list, 0, sizeof(uuid16_list));
510
511 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200512 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300513 u16 uuid16;
514
515 uuid16 = get_uuid16(uuid->uuid);
516 if (uuid16 == 0)
517 return;
518
519 if (uuid16 < 0x1100)
520 continue;
521
522 if (uuid16 == PNP_INFO_SVCLASS_ID)
523 continue;
524
525 /* Stop if not enough space to put next UUID */
526 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
527 truncated = 1;
528 break;
529 }
530
531 /* Check for duplicates */
532 for (i = 0; uuid16_list[i] != 0; i++)
533 if (uuid16_list[i] == uuid16)
534 break;
535
536 if (uuid16_list[i] == 0) {
537 uuid16_list[i] = uuid16;
538 eir_len += sizeof(u16);
539 }
540 }
541
542 if (uuid16_list[0] != 0) {
543 u8 *length = ptr;
544
545 /* EIR Data type */
546 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
547
548 ptr += 2;
549 eir_len += 2;
550
551 for (i = 0; uuid16_list[i] != 0; i++) {
552 *ptr++ = (uuid16_list[i] & 0x00ff);
553 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
554 }
555
556 /* EIR Data length */
557 *length = (i * sizeof(u16)) + 1;
558 }
559}
560
561static int update_eir(struct hci_dev *hdev)
562{
563 struct hci_cp_write_eir cp;
564
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200565 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200566 return 0;
567
Johan Hedberg976eb202012-10-24 21:12:01 +0300568 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300569 return 0;
570
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200571 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300572 return 0;
573
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200574 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300575 return 0;
576
577 memset(&cp, 0, sizeof(cp));
578
579 create_eir(hdev, cp.data);
580
581 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
582 return 0;
583
584 memcpy(hdev->eir, cp.data, sizeof(cp.data));
585
586 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
587}
588
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200589static u8 get_service_classes(struct hci_dev *hdev)
590{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300591 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200592 u8 val = 0;
593
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300594 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200596
597 return val;
598}
599
600static int update_class(struct hci_dev *hdev)
601{
602 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200603 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200604
605 BT_DBG("%s", hdev->name);
606
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200607 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200608 return 0;
609
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200610 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200611 return 0;
612
613 cod[0] = hdev->minor_class;
614 cod[1] = hdev->major_class;
615 cod[2] = get_service_classes(hdev);
616
617 if (memcmp(cod, hdev->dev_class, 3) == 0)
618 return 0;
619
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200620 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
621 if (err == 0)
622 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
623
624 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200625}
626
Johan Hedberg7d785252011-12-15 00:47:39 +0200627static void service_cache_off(struct work_struct *work)
628{
629 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300630 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200631
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200632 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200633 return;
634
635 hci_dev_lock(hdev);
636
637 update_eir(hdev);
638 update_class(hdev);
639
640 hci_dev_unlock(hdev);
641}
642
Johan Hedberg6a919082012-02-28 06:17:26 +0200643static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200644{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200645 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200646 return;
647
Johan Hedberg4f87da82012-03-02 19:55:56 +0200648 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200649
Johan Hedberg4f87da82012-03-02 19:55:56 +0200650 /* Non-mgmt controlled devices get this bit set
651 * implicitly so that pairing works for them, however
652 * for mgmt we require user-space to explicitly enable
653 * it
654 */
655 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200656}
657
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200658static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300659 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200660{
661 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200662
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200663 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300665 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200666
Johan Hedberg03811012010-12-08 00:21:06 +0200667 memset(&rp, 0, sizeof(rp));
668
Johan Hedberg03811012010-12-08 00:21:06 +0200669 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200670
671 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200672 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200673
674 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
675 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
676
677 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200678
679 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200680 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200681
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300682 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200683
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200684 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300685 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200686}
687
688static void mgmt_pending_free(struct pending_cmd *cmd)
689{
690 sock_put(cmd->sk);
691 kfree(cmd->param);
692 kfree(cmd);
693}
694
695static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300696 struct hci_dev *hdev, void *data,
697 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200698{
699 struct pending_cmd *cmd;
700
Andre Guedes12b94562012-06-07 19:05:45 -0300701 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200702 if (!cmd)
703 return NULL;
704
705 cmd->opcode = opcode;
706 cmd->index = hdev->id;
707
Andre Guedes12b94562012-06-07 19:05:45 -0300708 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200709 if (!cmd->param) {
710 kfree(cmd);
711 return NULL;
712 }
713
714 if (data)
715 memcpy(cmd->param, data, len);
716
717 cmd->sk = sk;
718 sock_hold(sk);
719
720 list_add(&cmd->list, &hdev->mgmt_pending);
721
722 return cmd;
723}
724
725static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300726 void (*cb)(struct pending_cmd *cmd,
727 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300728 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200729{
730 struct list_head *p, *n;
731
732 list_for_each_safe(p, n, &hdev->mgmt_pending) {
733 struct pending_cmd *cmd;
734
735 cmd = list_entry(p, struct pending_cmd, list);
736
737 if (opcode > 0 && cmd->opcode != opcode)
738 continue;
739
740 cb(cmd, data);
741 }
742}
743
744static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
745{
746 struct pending_cmd *cmd;
747
748 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
749 if (cmd->opcode == opcode)
750 return cmd;
751 }
752
753 return NULL;
754}
755
756static void mgmt_pending_remove(struct pending_cmd *cmd)
757{
758 list_del(&cmd->list);
759 mgmt_pending_free(cmd);
760}
761
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200762static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200763{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200764 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200765
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200766 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300767 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200768}
769
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200770static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300771 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200772{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300773 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200774 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200775 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200776
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200777 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200778
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300779 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200780
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100781 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
782 cancel_delayed_work(&hdev->power_off);
783
784 if (cp->val) {
785 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
786 mgmt_powered(hdev, 1);
787 goto failed;
788 }
789 }
790
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200791 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200792 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200793 goto failed;
794 }
795
796 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200797 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300798 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200799 goto failed;
800 }
801
802 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
803 if (!cmd) {
804 err = -ENOMEM;
805 goto failed;
806 }
807
808 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200809 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200810 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200811 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200812
813 err = 0;
814
815failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300816 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200817 return err;
818}
819
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300820static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
821 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200822{
823 struct sk_buff *skb;
824 struct mgmt_hdr *hdr;
825
Andre Guedes790eff42012-06-07 19:05:46 -0300826 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200827 if (!skb)
828 return -ENOMEM;
829
830 hdr = (void *) skb_put(skb, sizeof(*hdr));
831 hdr->opcode = cpu_to_le16(event);
832 if (hdev)
833 hdr->index = cpu_to_le16(hdev->id);
834 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530835 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200836 hdr->len = cpu_to_le16(data_len);
837
838 if (data)
839 memcpy(skb_put(skb, data_len), data, data_len);
840
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100841 /* Time stamp */
842 __net_timestamp(skb);
843
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200844 hci_send_to_control(skb, skip_sk);
845 kfree_skb(skb);
846
847 return 0;
848}
849
850static int new_settings(struct hci_dev *hdev, struct sock *skip)
851{
852 __le32 ev;
853
854 ev = cpu_to_le32(get_current_settings(hdev));
855
856 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
857}
858
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200859static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300860 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300862 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200863 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200864 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200865 u8 scan;
866 int err;
867
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200868 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200869
Johan Hedberg33c525c2012-10-24 21:11:58 +0300870 if (!lmp_bredr_capable(hdev))
871 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
872 MGMT_STATUS_NOT_SUPPORTED);
873
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700874 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100875 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200876 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300877 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200878
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300879 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200880
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200881 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200882 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300883 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200884 goto failed;
885 }
886
887 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300888 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200889 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300890 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200891 goto failed;
892 }
893
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200894 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200895 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300896 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200897 goto failed;
898 }
899
900 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200901 bool changed = false;
902
903 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
904 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
905 changed = true;
906 }
907
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200908 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200909 if (err < 0)
910 goto failed;
911
912 if (changed)
913 err = new_settings(hdev, sk);
914
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200915 goto failed;
916 }
917
918 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100919 if (hdev->discov_timeout > 0) {
920 cancel_delayed_work(&hdev->discov_off);
921 hdev->discov_timeout = 0;
922 }
923
924 if (cp->val && timeout > 0) {
925 hdev->discov_timeout = timeout;
926 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
927 msecs_to_jiffies(hdev->discov_timeout * 1000));
928 }
929
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200930 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200931 goto failed;
932 }
933
934 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
935 if (!cmd) {
936 err = -ENOMEM;
937 goto failed;
938 }
939
940 scan = SCAN_PAGE;
941
942 if (cp->val)
943 scan |= SCAN_INQUIRY;
944 else
945 cancel_delayed_work(&hdev->discov_off);
946
947 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
948 if (err < 0)
949 mgmt_pending_remove(cmd);
950
Johan Hedberg03811012010-12-08 00:21:06 +0200951 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200952 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200953
954failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300955 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200956 return err;
957}
958
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200959static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300960 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200961{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300962 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200963 struct pending_cmd *cmd;
964 u8 scan;
965 int err;
966
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200967 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200968
Johan Hedberg33c525c2012-10-24 21:11:58 +0300969 if (!lmp_bredr_capable(hdev))
970 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
971 MGMT_STATUS_NOT_SUPPORTED);
972
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300973 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200974
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200975 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200976 bool changed = false;
977
978 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
979 changed = true;
980
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200981 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200983 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200984 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
985 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
986 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200987
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200988 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200989 if (err < 0)
990 goto failed;
991
992 if (changed)
993 err = new_settings(hdev, sk);
994
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200995 goto failed;
996 }
997
998 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300999 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001000 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001001 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001002 goto failed;
1003 }
1004
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001005 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001006 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007 goto failed;
1008 }
1009
1010 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1011 if (!cmd) {
1012 err = -ENOMEM;
1013 goto failed;
1014 }
1015
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001016 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001018 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019 scan = 0;
1020
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001021 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001022 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001023 cancel_delayed_work(&hdev->discov_off);
1024 }
1025
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001026 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1027 if (err < 0)
1028 mgmt_pending_remove(cmd);
1029
1030failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001031 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 return err;
1033}
1034
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001035static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001036 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001037{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001038 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001039 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001041 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001043 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001044
1045 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001046 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001047 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001048 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001049
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001050 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001051 if (err < 0)
1052 goto failed;
1053
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001054 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001055
1056failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001057 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001058 return err;
1059}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001060
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001061static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1062 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001063{
1064 struct mgmt_mode *cp = data;
1065 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001066 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001067 int err;
1068
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001069 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001070
Johan Hedberg33c525c2012-10-24 21:11:58 +03001071 if (!lmp_bredr_capable(hdev))
1072 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1073 MGMT_STATUS_NOT_SUPPORTED);
1074
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001075 hci_dev_lock(hdev);
1076
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001077 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001078 bool changed = false;
1079
1080 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001081 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001082 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1083 changed = true;
1084 }
1085
1086 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1087 if (err < 0)
1088 goto failed;
1089
1090 if (changed)
1091 err = new_settings(hdev, sk);
1092
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001093 goto failed;
1094 }
1095
1096 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001097 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001098 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001099 goto failed;
1100 }
1101
1102 val = !!cp->val;
1103
1104 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1105 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1106 goto failed;
1107 }
1108
1109 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1110 if (!cmd) {
1111 err = -ENOMEM;
1112 goto failed;
1113 }
1114
1115 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1116 if (err < 0) {
1117 mgmt_pending_remove(cmd);
1118 goto failed;
1119 }
1120
1121failed:
1122 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001123 return err;
1124}
1125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001126static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001127{
1128 struct mgmt_mode *cp = data;
1129 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001130 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001131 int err;
1132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001133 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001134
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001135 hci_dev_lock(hdev);
1136
Andre Guedes9a1a1992012-07-24 15:03:48 -03001137 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001138 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001139 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001140 goto failed;
1141 }
1142
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001143 val = !!cp->val;
1144
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001145 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001146 bool changed = false;
1147
1148 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1149 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1150 changed = true;
1151 }
1152
1153 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1154 if (err < 0)
1155 goto failed;
1156
1157 if (changed)
1158 err = new_settings(hdev, sk);
1159
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001160 goto failed;
1161 }
1162
1163 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001164 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1165 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001166 goto failed;
1167 }
1168
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001169 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1170 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1171 goto failed;
1172 }
1173
1174 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1175 if (!cmd) {
1176 err = -ENOMEM;
1177 goto failed;
1178 }
1179
1180 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1181 if (err < 0) {
1182 mgmt_pending_remove(cmd);
1183 goto failed;
1184 }
1185
1186failed:
1187 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001188 return err;
1189}
1190
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001191static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001192{
1193 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001197 if (!enable_hs)
1198 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001199 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001200
1201 if (cp->val)
1202 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1203 else
1204 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1205
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001206 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001207}
1208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001209static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001210{
1211 struct mgmt_mode *cp = data;
1212 struct hci_cp_write_le_host_supported hci_cp;
1213 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001214 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001215 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001217 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001218
Johan Hedberg1de028c2012-02-29 19:55:35 -08001219 hci_dev_lock(hdev);
1220
Andre Guedesc383ddc2012-07-24 15:03:47 -03001221 if (!lmp_le_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001222 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001223 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001224 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001225 }
1226
1227 val = !!cp->val;
Johan Hedberg976eb202012-10-24 21:12:01 +03001228 enabled = !!lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001229
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001230 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001231 bool changed = false;
1232
1233 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1234 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1235 changed = true;
1236 }
1237
1238 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1239 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001240 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001241
1242 if (changed)
1243 err = new_settings(hdev, sk);
1244
Johan Hedberg1de028c2012-02-29 19:55:35 -08001245 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001246 }
1247
1248 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001249 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001250 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001251 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001252 }
1253
1254 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1255 if (!cmd) {
1256 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001257 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001258 }
1259
1260 memset(&hci_cp, 0, sizeof(hci_cp));
1261
1262 if (val) {
1263 hci_cp.le = val;
Johan Hedberg976eb202012-10-24 21:12:01 +03001264 hci_cp.simul = !!lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001265 }
1266
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001267 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1268 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301269 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001270 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001271
Johan Hedberg1de028c2012-02-29 19:55:35 -08001272unlock:
1273 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001274 return err;
1275}
1276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001278{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001279 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001280 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001281 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001282 int err;
1283
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001284 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001285
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001286 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001287
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001288 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001289 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001290 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001291 goto failed;
1292 }
1293
Andre Guedes92c4c202012-06-07 19:05:44 -03001294 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001295 if (!uuid) {
1296 err = -ENOMEM;
1297 goto failed;
1298 }
1299
1300 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001301 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001302
1303 list_add(&uuid->list, &hdev->uuids);
1304
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001305 err = update_class(hdev);
1306 if (err < 0)
1307 goto failed;
1308
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001309 err = update_eir(hdev);
1310 if (err < 0)
1311 goto failed;
1312
Johan Hedberg90e70452012-02-23 23:09:40 +02001313 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001314 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001315 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001316 goto failed;
1317 }
1318
1319 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301320 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001321 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001322
1323failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001324 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325 return err;
1326}
1327
Johan Hedberg24b78d02012-02-23 23:24:30 +02001328static bool enable_service_cache(struct hci_dev *hdev)
1329{
1330 if (!hdev_is_powered(hdev))
1331 return false;
1332
1333 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001334 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001335 return true;
1336 }
1337
1338 return false;
1339}
1340
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001341static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001342 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001343{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001344 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001345 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001346 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 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 +02001348 int err, found;
1349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001350 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001351
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001352 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001353
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001354 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001355 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001356 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001357 goto unlock;
1358 }
1359
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001360 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1361 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001362
Johan Hedberg24b78d02012-02-23 23:24:30 +02001363 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001364 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001365 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001366 goto unlock;
1367 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001368
Johan Hedberg9246a862012-02-23 21:33:16 +02001369 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001370 }
1371
1372 found = 0;
1373
1374 list_for_each_safe(p, n, &hdev->uuids) {
1375 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1376
1377 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1378 continue;
1379
1380 list_del(&match->list);
1381 found++;
1382 }
1383
1384 if (found == 0) {
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_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001387 goto unlock;
1388 }
1389
Johan Hedberg9246a862012-02-23 21:33:16 +02001390update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001391 err = update_class(hdev);
1392 if (err < 0)
1393 goto unlock;
1394
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001395 err = update_eir(hdev);
1396 if (err < 0)
1397 goto unlock;
1398
Johan Hedberg90e70452012-02-23 23:09:40 +02001399 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001400 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001401 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001402 goto unlock;
1403 }
1404
1405 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301406 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001407 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001408
1409unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001410 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001411 return err;
1412}
1413
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001414static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001415 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001416{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001417 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001418 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001419 int err;
1420
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001421 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001422
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001423 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001424
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001425 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001426 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001427 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001428 goto unlock;
1429 }
1430
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001431 hdev->major_class = cp->major;
1432 hdev->minor_class = cp->minor;
1433
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001434 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001435 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001436 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001437 goto unlock;
1438 }
1439
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001440 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001441 hci_dev_unlock(hdev);
1442 cancel_delayed_work_sync(&hdev->service_cache);
1443 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001444 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001445 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001446
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001448 if (err < 0)
1449 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001450
Johan Hedberg90e70452012-02-23 23:09:40 +02001451 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001452 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001453 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001454 goto unlock;
1455 }
1456
1457 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301458 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001459 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001460
Johan Hedbergb5235a62012-02-21 14:32:24 +02001461unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001462 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001463 return err;
1464}
1465
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001466static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001467 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001468{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001469 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001470 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001471 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001472
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001473 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001474
Johan Hedberg86742e12011-11-07 23:13:38 +02001475 expected_len = sizeof(*cp) + key_count *
1476 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001477 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001478 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001479 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001480 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001481 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001482 }
1483
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001484 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001485 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001486
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001487 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001488
1489 hci_link_keys_clear(hdev);
1490
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001491 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001492
1493 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001494 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001495 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001496 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001497
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001498 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001499 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001500
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001501 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001502 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001503 }
1504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001505 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001506
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001507 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001509 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001510}
1511
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001512static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001513 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001514{
1515 struct mgmt_ev_device_unpaired ev;
1516
1517 bacpy(&ev.addr.bdaddr, bdaddr);
1518 ev.addr.type = addr_type;
1519
1520 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001521 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001522}
1523
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001524static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001525 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001527 struct mgmt_cp_unpair_device *cp = data;
1528 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001529 struct hci_cp_disconnect dc;
1530 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001531 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001532 int err;
1533
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001534 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001535
Johan Hedberga8a1d192011-11-10 15:54:38 +02001536 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001537 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1538 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001539
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001540 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001541 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001542 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001543 goto unlock;
1544 }
1545
Andre Guedes591f47f2012-04-24 21:02:49 -03001546 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001547 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1548 else
1549 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001550
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001551 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001552 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001553 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001554 goto unlock;
1555 }
1556
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001557 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001558 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001559 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001560 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001561 else
1562 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001563 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001564 } else {
1565 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001566 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001567
Johan Hedberga8a1d192011-11-10 15:54:38 +02001568 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001569 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001570 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001571 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001572 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001573 }
1574
Johan Hedberg124f6e32012-02-09 13:50:12 +02001575 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001576 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001577 if (!cmd) {
1578 err = -ENOMEM;
1579 goto unlock;
1580 }
1581
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001582 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001583 dc.reason = 0x13; /* Remote User Terminated Connection */
1584 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1585 if (err < 0)
1586 mgmt_pending_remove(cmd);
1587
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001588unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001589 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001590 return err;
1591}
1592
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001593static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001594 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001595{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001596 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001597 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001598 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001599 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001600 int err;
1601
1602 BT_DBG("");
1603
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001604 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001605
1606 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001607 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001608 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001609 goto failed;
1610 }
1611
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001612 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001613 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001614 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615 goto failed;
1616 }
1617
Andre Guedes591f47f2012-04-24 21:02:49 -03001618 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001619 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1620 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001621 else
1622 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001623
Vishal Agarwalf9607272012-06-13 05:32:43 +05301624 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001625 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001626 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001627 goto failed;
1628 }
1629
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001630 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001631 if (!cmd) {
1632 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001633 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001634 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001635
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001636 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001637 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001638
1639 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1640 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001641 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001642
1643failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001644 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001645 return err;
1646}
1647
Andre Guedes57c14772012-04-24 21:02:50 -03001648static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001649{
1650 switch (link_type) {
1651 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001652 switch (addr_type) {
1653 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001654 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001655
Johan Hedberg48264f02011-11-09 13:58:58 +02001656 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001657 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001658 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001659 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001660
Johan Hedberg4c659c32011-11-07 23:13:39 +02001661 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001662 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001663 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001664 }
1665}
1666
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001667static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1668 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001669{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001670 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001671 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001672 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001673 int err;
1674 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001675
1676 BT_DBG("");
1677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001678 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001679
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001680 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001681 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001682 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001683 goto unlock;
1684 }
1685
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001686 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001687 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1688 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001689 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001690 }
1691
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001692 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001693 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001694 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001695 err = -ENOMEM;
1696 goto unlock;
1697 }
1698
Johan Hedberg2784eb42011-01-21 13:56:35 +02001699 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001700 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001701 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1702 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001703 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001704 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001705 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001706 continue;
1707 i++;
1708 }
1709
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001710 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001711
Johan Hedberg4c659c32011-11-07 23:13:39 +02001712 /* Recalculate length in case of filtered SCO connections, etc */
1713 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001714
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001715 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001716 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001717
Johan Hedberga38528f2011-01-22 06:46:43 +02001718 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001719
1720unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001721 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001722 return err;
1723}
1724
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001725static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001726 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001727{
1728 struct pending_cmd *cmd;
1729 int err;
1730
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001731 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001732 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001733 if (!cmd)
1734 return -ENOMEM;
1735
Johan Hedbergd8457692012-02-17 14:24:57 +02001736 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001737 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001738 if (err < 0)
1739 mgmt_pending_remove(cmd);
1740
1741 return err;
1742}
1743
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001744static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001745 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001746{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001747 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001748 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001749 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001750 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001751 int err;
1752
1753 BT_DBG("");
1754
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001755 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001756
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001757 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001758 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001759 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001760 goto failed;
1761 }
1762
Johan Hedbergd8457692012-02-17 14:24:57 +02001763 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001764 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001766 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001767 goto failed;
1768 }
1769
1770 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001771 struct mgmt_cp_pin_code_neg_reply ncp;
1772
1773 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001774
1775 BT_ERR("PIN code is not 16 bytes long");
1776
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001777 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001778 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001779 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001780 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001781
1782 goto failed;
1783 }
1784
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001785 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001786 if (!cmd) {
1787 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001788 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001789 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001790
Johan Hedbergd8457692012-02-17 14:24:57 +02001791 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001792 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001793 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001794
1795 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1796 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001797 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798
1799failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001800 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001801 return err;
1802}
1803
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001804static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1805 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001806{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001807 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001808
1809 BT_DBG("");
1810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001812
1813 hdev->io_capability = cp->io_capability;
1814
1815 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001816 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001818 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001820 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1821 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001822}
1823
Gustavo Padovan6039aa732012-05-23 04:04:18 -03001824static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001825{
1826 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001827 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001828
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001829 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001830 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1831 continue;
1832
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833 if (cmd->user_data != conn)
1834 continue;
1835
1836 return cmd;
1837 }
1838
1839 return NULL;
1840}
1841
1842static void pairing_complete(struct pending_cmd *cmd, u8 status)
1843{
1844 struct mgmt_rp_pair_device rp;
1845 struct hci_conn *conn = cmd->user_data;
1846
Johan Hedbergba4e5642011-11-11 00:07:34 +02001847 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001848 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001849
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001850 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001851 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001852
1853 /* So we don't get further callbacks for this connection */
1854 conn->connect_cfm_cb = NULL;
1855 conn->security_cfm_cb = NULL;
1856 conn->disconn_cfm_cb = NULL;
1857
1858 hci_conn_put(conn);
1859
Johan Hedberga664b5b2011-02-19 12:06:02 -03001860 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001861}
1862
1863static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1864{
1865 struct pending_cmd *cmd;
1866
1867 BT_DBG("status %u", status);
1868
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001869 cmd = find_pairing(conn);
1870 if (!cmd)
1871 BT_DBG("Unable to find a pending command");
1872 else
Johan Hedberge2113262012-02-18 15:20:03 +02001873 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874}
1875
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301876static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1877{
1878 struct pending_cmd *cmd;
1879
1880 BT_DBG("status %u", status);
1881
1882 if (!status)
1883 return;
1884
1885 cmd = find_pairing(conn);
1886 if (!cmd)
1887 BT_DBG("Unable to find a pending command");
1888 else
1889 pairing_complete(cmd, mgmt_status(status));
1890}
1891
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001892static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001893 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001895 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001896 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897 struct pending_cmd *cmd;
1898 u8 sec_level, auth_type;
1899 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 int err;
1901
1902 BT_DBG("");
1903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001904 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001905
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001906 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001907 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001908 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001909 goto unlock;
1910 }
1911
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001912 sec_level = BT_SECURITY_MEDIUM;
1913 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001915 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001916 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001917
Andre Guedes591f47f2012-04-24 21:02:49 -03001918 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001919 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1920 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001921 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001922 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1923 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001924
Johan Hedberg1425acb2011-11-11 00:07:35 +02001925 memset(&rp, 0, sizeof(rp));
1926 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1927 rp.addr.type = cp->addr.type;
1928
Ville Tervo30e76272011-02-22 16:10:53 -03001929 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001930 int status;
1931
1932 if (PTR_ERR(conn) == -EBUSY)
1933 status = MGMT_STATUS_BUSY;
1934 else
1935 status = MGMT_STATUS_CONNECT_FAILED;
1936
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001937 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001938 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001939 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940 goto unlock;
1941 }
1942
1943 if (conn->connect_cfm_cb) {
1944 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001945 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001946 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001947 goto unlock;
1948 }
1949
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001950 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 if (!cmd) {
1952 err = -ENOMEM;
1953 hci_conn_put(conn);
1954 goto unlock;
1955 }
1956
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001957 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001958 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001959 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301960 else
1961 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001962
Johan Hedberge9a416b2011-02-19 12:05:56 -03001963 conn->security_cfm_cb = pairing_complete_cb;
1964 conn->disconn_cfm_cb = pairing_complete_cb;
1965 conn->io_capability = cp->io_cap;
1966 cmd->user_data = conn;
1967
1968 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001969 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03001970 pairing_complete(cmd, 0);
1971
1972 err = 0;
1973
1974unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001975 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001976 return err;
1977}
1978
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001979static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1980 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001981{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001982 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001983 struct pending_cmd *cmd;
1984 struct hci_conn *conn;
1985 int err;
1986
1987 BT_DBG("");
1988
Johan Hedberg28424702012-02-02 04:02:29 +02001989 hci_dev_lock(hdev);
1990
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001991 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001992 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001993 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001994 goto unlock;
1995 }
1996
Johan Hedberg28424702012-02-02 04:02:29 +02001997 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1998 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001999 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002000 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002001 goto unlock;
2002 }
2003
2004 conn = cmd->user_data;
2005
2006 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002007 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002008 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002009 goto unlock;
2010 }
2011
2012 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002016unlock:
2017 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002018 return err;
2019}
2020
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002021static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002022 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2023 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002024{
Johan Hedberga5c29682011-02-19 12:05:57 -03002025 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002026 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002027 int err;
2028
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002029 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002030
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002031 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002032 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002033 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002034 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002035 }
2036
Andre Guedes591f47f2012-04-24 21:02:49 -03002037 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002038 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2039 else
Brian Gix47c15e22011-11-16 13:53:14 -08002040 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002041
Johan Hedberg272d90d2012-02-09 15:26:12 +02002042 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002043 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002044 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002045 goto done;
2046 }
2047
Andre Guedes591f47f2012-04-24 21:02:49 -03002048 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002049 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002050 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002051
Brian Gix5fe57d92011-12-21 16:12:13 -08002052 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002054 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002055 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002056 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002057 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002058
Brian Gix47c15e22011-11-16 13:53:14 -08002059 goto done;
2060 }
2061
Brian Gix0df4c182011-11-16 13:53:13 -08002062 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002063 if (!cmd) {
2064 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002065 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002066 }
2067
Brian Gix0df4c182011-11-16 13:53:13 -08002068 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002069 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2070 struct hci_cp_user_passkey_reply cp;
2071
2072 bacpy(&cp.bdaddr, bdaddr);
2073 cp.passkey = passkey;
2074 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2075 } else
2076 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2077
Johan Hedberga664b5b2011-02-19 12:06:02 -03002078 if (err < 0)
2079 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002080
Brian Gix0df4c182011-11-16 13:53:13 -08002081done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002082 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002083 return err;
2084}
2085
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302086static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2087 void *data, u16 len)
2088{
2089 struct mgmt_cp_pin_code_neg_reply *cp = data;
2090
2091 BT_DBG("");
2092
2093 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2094 MGMT_OP_PIN_CODE_NEG_REPLY,
2095 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2096}
2097
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2099 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002100{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002101 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002102
2103 BT_DBG("");
2104
2105 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002106 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002107 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002110 MGMT_OP_USER_CONFIRM_REPLY,
2111 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002112}
2113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002116{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002117 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002118
2119 BT_DBG("");
2120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002121 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002122 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2123 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002124}
2125
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002126static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2127 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002128{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002129 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002130
2131 BT_DBG("");
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002134 MGMT_OP_USER_PASSKEY_REPLY,
2135 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002136}
2137
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002138static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002139 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002140{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002141 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002142
2143 BT_DBG("");
2144
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002145 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002146 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2147 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002148}
2149
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002150static int update_name(struct hci_dev *hdev, const char *name)
2151{
2152 struct hci_cp_write_local_name cp;
2153
2154 memcpy(cp.name, name, sizeof(cp.name));
2155
2156 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2157}
2158
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002159static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002160 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002161{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002162 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002163 struct pending_cmd *cmd;
2164 int err;
2165
2166 BT_DBG("");
2167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002168 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002169
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002170 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002171
Johan Hedbergb5235a62012-02-21 14:32:24 +02002172 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002173 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002174
2175 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002177 if (err < 0)
2178 goto failed;
2179
2180 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002181 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002182
Johan Hedbergb5235a62012-02-21 14:32:24 +02002183 goto failed;
2184 }
2185
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002186 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002187 if (!cmd) {
2188 err = -ENOMEM;
2189 goto failed;
2190 }
2191
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002192 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002193 if (err < 0)
2194 mgmt_pending_remove(cmd);
2195
2196failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002197 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002198 return err;
2199}
2200
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002201static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002202 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002203{
Szymon Jancc35938b2011-03-22 13:12:21 +01002204 struct pending_cmd *cmd;
2205 int err;
2206
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002207 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002208
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002209 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002210
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002211 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002212 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002213 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002214 goto unlock;
2215 }
2216
Andre Guedes9a1a1992012-07-24 15:03:48 -03002217 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002218 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002219 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002220 goto unlock;
2221 }
2222
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002223 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002224 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002225 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002226 goto unlock;
2227 }
2228
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002229 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002230 if (!cmd) {
2231 err = -ENOMEM;
2232 goto unlock;
2233 }
2234
2235 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2236 if (err < 0)
2237 mgmt_pending_remove(cmd);
2238
2239unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002241 return err;
2242}
2243
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002244static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002245 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002246{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002247 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002248 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002249 int err;
2250
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002251 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002252
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002253 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002254
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002255 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002256 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002257 MGMT_STATUS_NOT_POWERED, &cp->addr,
2258 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002259 goto unlock;
2260 }
2261
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002262 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002263 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002264 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002265 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002266 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002267 status = 0;
2268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002269 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002270 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002271
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002272unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002273 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002274 return err;
2275}
2276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002277static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002278 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002279{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002280 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002281 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002282 int err;
2283
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002284 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002285
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002286 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002287
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002288 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002289 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002290 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2291 MGMT_STATUS_NOT_POWERED, &cp->addr,
2292 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002293 goto unlock;
2294 }
2295
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002296 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002297 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002298 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002299 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002300 status = 0;
2301
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002302 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002303 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002304
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002305unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002306 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002307 return err;
2308}
2309
Andre Guedes5e0452c2012-02-17 20:39:38 -03002310int mgmt_interleaved_discovery(struct hci_dev *hdev)
2311{
2312 int err;
2313
2314 BT_DBG("%s", hdev->name);
2315
2316 hci_dev_lock(hdev);
2317
2318 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2319 if (err < 0)
2320 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2321
2322 hci_dev_unlock(hdev);
2323
2324 return err;
2325}
2326
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002327static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002328 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002329{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002330 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002331 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002332 int err;
2333
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002334 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002335
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002336 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002337
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002338 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002339 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002341 goto failed;
2342 }
2343
Andre Guedes642be6c2012-03-21 00:03:37 -03002344 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2345 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2346 MGMT_STATUS_BUSY);
2347 goto failed;
2348 }
2349
Johan Hedbergff9ef572012-01-04 14:23:45 +02002350 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002351 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002352 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002353 goto failed;
2354 }
2355
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002356 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002357 if (!cmd) {
2358 err = -ENOMEM;
2359 goto failed;
2360 }
2361
Andre Guedes4aab14e2012-02-17 20:39:36 -03002362 hdev->discovery.type = cp->type;
2363
2364 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002365 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002366 if (lmp_bredr_capable(hdev))
2367 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2368 else
2369 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002370 break;
2371
2372 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002373 if (lmp_host_le_capable(hdev))
2374 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002376 else
2377 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002378 break;
2379
Andre Guedes5e0452c2012-02-17 20:39:38 -03002380 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002381 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2382 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002383 LE_SCAN_WIN,
2384 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002385 else
2386 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002387 break;
2388
Andre Guedesf39799f2012-02-17 20:39:35 -03002389 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002390 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002391 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002392
Johan Hedberg14a53662011-04-27 10:29:56 -04002393 if (err < 0)
2394 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002395 else
2396 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002397
2398failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002399 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002400 return err;
2401}
2402
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002403static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002404 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002405{
Johan Hedbergd9306502012-02-20 23:25:18 +02002406 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002407 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002408 struct hci_cp_remote_name_req_cancel cp;
2409 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002410 int err;
2411
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002412 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002413
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002414 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002415
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002416 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002417 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002418 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2419 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002420 goto unlock;
2421 }
2422
2423 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002424 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002425 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2426 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002427 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002428 }
2429
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002430 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002431 if (!cmd) {
2432 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002433 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002434 }
2435
Andre Guedese0d9727e2012-03-20 15:15:36 -03002436 switch (hdev->discovery.state) {
2437 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002438 if (test_bit(HCI_INQUIRY, &hdev->flags))
2439 err = hci_cancel_inquiry(hdev);
2440 else
2441 err = hci_cancel_le_scan(hdev);
2442
Andre Guedese0d9727e2012-03-20 15:15:36 -03002443 break;
2444
2445 case DISCOVERY_RESOLVING:
2446 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002447 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002448 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002449 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002450 err = cmd_complete(sk, hdev->id,
2451 MGMT_OP_STOP_DISCOVERY, 0,
2452 &mgmt_cp->type,
2453 sizeof(mgmt_cp->type));
2454 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2455 goto unlock;
2456 }
2457
2458 bacpy(&cp.bdaddr, &e->data.bdaddr);
2459 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2460 sizeof(cp), &cp);
2461
2462 break;
2463
2464 default:
2465 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2466 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002467 }
2468
Johan Hedberg14a53662011-04-27 10:29:56 -04002469 if (err < 0)
2470 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002471 else
2472 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002473
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002474unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002475 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002476 return err;
2477}
2478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002481{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002482 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002483 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002484 int err;
2485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002486 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002487
Johan Hedberg561aafb2012-01-04 13:31:59 +02002488 hci_dev_lock(hdev);
2489
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002490 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002491 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002492 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002493 goto failed;
2494 }
2495
Johan Hedberga198e7b2012-02-17 14:27:06 +02002496 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002497 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002499 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002500 goto failed;
2501 }
2502
2503 if (cp->name_known) {
2504 e->name_state = NAME_KNOWN;
2505 list_del(&e->list);
2506 } else {
2507 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002508 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002509 }
2510
2511 err = 0;
2512
2513failed:
2514 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002515 return err;
2516}
2517
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002518static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002519 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002520{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002521 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002522 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002523 int err;
2524
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002525 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002526
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002527 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002528
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002529 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002530 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002531 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002532 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002533 status = 0;
2534
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002535 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002539
2540 return err;
2541}
2542
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002543static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002544 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002545{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002546 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002547 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002548 int err;
2549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002550 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002551
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002552 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002553
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002554 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002555 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002556 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002557 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002558 status = 0;
2559
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002560 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002561 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002562
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002563 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002564
2565 return err;
2566}
2567
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002568static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2569 u16 len)
2570{
2571 struct mgmt_cp_set_device_id *cp = data;
2572 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002573 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002574
2575 BT_DBG("%s", hdev->name);
2576
Szymon Jancc72d4b82012-03-16 16:02:57 +01002577 source = __le16_to_cpu(cp->source);
2578
2579 if (source > 0x0002)
2580 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2581 MGMT_STATUS_INVALID_PARAMS);
2582
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002583 hci_dev_lock(hdev);
2584
Szymon Jancc72d4b82012-03-16 16:02:57 +01002585 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002586 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2587 hdev->devid_product = __le16_to_cpu(cp->product);
2588 hdev->devid_version = __le16_to_cpu(cp->version);
2589
2590 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2591
2592 update_eir(hdev);
2593
2594 hci_dev_unlock(hdev);
2595
2596 return err;
2597}
2598
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002599static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002600 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002601{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002602 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002603 struct hci_cp_write_page_scan_activity acp;
2604 u8 type;
2605 int err;
2606
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002607 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002608
Johan Hedberg33c525c2012-10-24 21:11:58 +03002609 if (!lmp_bredr_capable(hdev))
2610 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2611 MGMT_STATUS_NOT_SUPPORTED);
2612
Johan Hedberg5400c042012-02-21 16:40:33 +02002613 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002614 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002615 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002616
2617 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002619 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002620
2621 hci_dev_lock(hdev);
2622
Johan Hedbergf7c68692011-12-15 00:47:36 +02002623 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002624 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002625
Johan Hedberg83ce9a062012-06-28 13:44:30 +03002626 /* 160 msec page scan interval */
2627 acp.interval = __constant_cpu_to_le16(0x0100);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002628 } else {
2629 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002630
2631 /* default 1.28 sec page scan */
2632 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002633 }
2634
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002635 /* default 11.25 msec page scan window */
2636 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002637
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2639 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002640 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002641 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002642 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002643 goto done;
2644 }
2645
2646 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2647 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002650 goto done;
2651 }
2652
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002653 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002654 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002655done:
2656 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002657 return err;
2658}
2659
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002660static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002662{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002663 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2664 u16 key_count, expected_len;
2665 int i;
2666
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002667 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002668
2669 expected_len = sizeof(*cp) + key_count *
2670 sizeof(struct mgmt_ltk_info);
2671 if (expected_len != len) {
2672 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002673 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002674 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002675 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002676 }
2677
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002678 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002679
2680 hci_dev_lock(hdev);
2681
2682 hci_smp_ltks_clear(hdev);
2683
2684 for (i = 0; i < key_count; i++) {
2685 struct mgmt_ltk_info *key = &cp->keys[i];
2686 u8 type;
2687
2688 if (key->master)
2689 type = HCI_SMP_LTK;
2690 else
2691 type = HCI_SMP_LTK_SLAVE;
2692
Hemant Gupta4596fde2012-04-16 14:57:40 +05302693 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002694 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002695 type, 0, key->authenticated, key->val,
2696 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002697 }
2698
2699 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002700
2701 return 0;
2702}
2703
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002704static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002705 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2706 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002707 bool var_len;
2708 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002709} mgmt_handlers[] = {
2710 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002711 { read_version, false, MGMT_READ_VERSION_SIZE },
2712 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2713 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2714 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2715 { set_powered, false, MGMT_SETTING_SIZE },
2716 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2717 { set_connectable, false, MGMT_SETTING_SIZE },
2718 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2719 { set_pairable, false, MGMT_SETTING_SIZE },
2720 { set_link_security, false, MGMT_SETTING_SIZE },
2721 { set_ssp, false, MGMT_SETTING_SIZE },
2722 { set_hs, false, MGMT_SETTING_SIZE },
2723 { set_le, false, MGMT_SETTING_SIZE },
2724 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2725 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2726 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2727 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2728 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2729 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2730 { disconnect, false, MGMT_DISCONNECT_SIZE },
2731 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2732 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2733 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2734 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2735 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2736 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2737 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2738 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2739 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2740 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2741 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2742 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2743 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2744 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2745 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2746 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2747 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2748 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2749 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002750 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002751};
2752
2753
Johan Hedberg03811012010-12-08 00:21:06 +02002754int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2755{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002756 void *buf;
2757 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002758 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002759 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002761 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002762 int err;
2763
2764 BT_DBG("got %zu bytes", msglen);
2765
2766 if (msglen < sizeof(*hdr))
2767 return -EINVAL;
2768
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002769 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002770 if (!buf)
2771 return -ENOMEM;
2772
2773 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2774 err = -EFAULT;
2775 goto done;
2776 }
2777
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002778 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002779 opcode = __le16_to_cpu(hdr->opcode);
2780 index = __le16_to_cpu(hdr->index);
2781 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002782
2783 if (len != msglen - sizeof(*hdr)) {
2784 err = -EINVAL;
2785 goto done;
2786 }
2787
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002788 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002789 hdev = hci_dev_get(index);
2790 if (!hdev) {
2791 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002792 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002793 goto done;
2794 }
2795 }
2796
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002797 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002798 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002799 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002800 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002801 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002802 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002803 }
2804
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002805 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002806 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002807 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002808 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002809 goto done;
2810 }
2811
Johan Hedbergbe22b542012-03-01 22:24:41 +02002812 handler = &mgmt_handlers[opcode];
2813
2814 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002815 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002816 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002817 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002818 goto done;
2819 }
2820
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002821 if (hdev)
2822 mgmt_init_hdev(sk, hdev);
2823
2824 cp = buf + sizeof(*hdr);
2825
Johan Hedbergbe22b542012-03-01 22:24:41 +02002826 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002827 if (err < 0)
2828 goto done;
2829
Johan Hedberg03811012010-12-08 00:21:06 +02002830 err = msglen;
2831
2832done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002833 if (hdev)
2834 hci_dev_put(hdev);
2835
Johan Hedberg03811012010-12-08 00:21:06 +02002836 kfree(buf);
2837 return err;
2838}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002839
Johan Hedbergb24752f2011-11-03 14:40:33 +02002840static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2841{
2842 u8 *status = data;
2843
2844 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2845 mgmt_pending_remove(cmd);
2846}
2847
Johan Hedberg744cf192011-11-08 20:40:14 +02002848int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002849{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002850 if (!mgmt_valid_hdev(hdev))
2851 return -ENOTSUPP;
2852
Johan Hedberg744cf192011-11-08 20:40:14 +02002853 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002854}
2855
Johan Hedberg744cf192011-11-08 20:40:14 +02002856int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002857{
Johan Hedberg5f159032012-03-02 03:13:19 +02002858 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002859
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002860 if (!mgmt_valid_hdev(hdev))
2861 return -ENOTSUPP;
2862
Johan Hedberg744cf192011-11-08 20:40:14 +02002863 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002864
Johan Hedberg744cf192011-11-08 20:40:14 +02002865 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002866}
2867
Johan Hedberg73f22f62010-12-29 16:00:25 +02002868struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002869 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002870 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002871 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002872};
2873
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002874static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002875{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002876 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002877
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002878 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002879
2880 list_del(&cmd->list);
2881
2882 if (match->sk == NULL) {
2883 match->sk = cmd->sk;
2884 sock_hold(match->sk);
2885 }
2886
2887 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002888}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002889
Johan Hedberg7f0ae642012-10-24 21:11:57 +03002890static int set_bredr_scan(struct hci_dev *hdev)
2891{
2892 u8 scan = 0;
2893
2894 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2895 scan |= SCAN_PAGE;
2896 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2897 scan |= SCAN_INQUIRY;
2898
2899 if (!scan)
2900 return 0;
2901
2902 return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2903}
2904
Johan Hedberg744cf192011-11-08 20:40:14 +02002905int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002906{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002907 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002908 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002909
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002910 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2911 return 0;
2912
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002913 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002914
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002915 if (powered) {
Johan Hedberg6b4b73e2012-10-25 00:09:52 +03002916 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
2917 !lmp_host_ssp_capable(hdev)) {
Andrzej Kaczmarek3d1cbdd2012-08-29 10:02:08 +02002918 u8 ssp = 1;
2919
2920 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
2921 }
2922
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02002923 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
2924 struct hci_cp_write_le_host_supported cp;
2925
2926 cp.le = 1;
Johan Hedberg976eb202012-10-24 21:12:01 +03002927 cp.simul = !!lmp_le_br_capable(hdev);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02002928
Johan Hedberg430a61b2012-10-25 00:09:53 +03002929 /* Check first if we already have the right
2930 * host state (host features set)
2931 */
2932 if (cp.le != !!lmp_host_le_capable(hdev) ||
2933 cp.simul != !!lmp_host_le_br_capable(hdev))
2934 hci_send_cmd(hdev,
2935 HCI_OP_WRITE_LE_HOST_SUPPORTED,
2936 sizeof(cp), &cp);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02002937 }
2938
Johan Hedberg7f0ae642012-10-24 21:11:57 +03002939 if (lmp_bredr_capable(hdev)) {
2940 set_bredr_scan(hdev);
2941 update_class(hdev);
2942 update_name(hdev, hdev->dev_name);
2943 update_eir(hdev);
2944 }
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002945 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002946 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002947 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002948 }
2949
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002950 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002951
2952 if (match.sk)
2953 sock_put(match.sk);
2954
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002955 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002956}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002957
Johan Hedberg744cf192011-11-08 20:40:14 +02002958int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002959{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002960 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002961 bool changed = false;
2962 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002963
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002964 if (discoverable) {
2965 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2966 changed = true;
2967 } else {
2968 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2969 changed = true;
2970 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002971
Johan Hedberged9b5f22012-02-21 20:47:06 +02002972 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002973 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002974
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002975 if (changed)
2976 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002977
Johan Hedberg73f22f62010-12-29 16:00:25 +02002978 if (match.sk)
2979 sock_put(match.sk);
2980
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002981 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002982}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002983
Johan Hedberg744cf192011-11-08 20:40:14 +02002984int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002985{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002986 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002987 bool changed = false;
2988 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002989
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002990 if (connectable) {
2991 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2992 changed = true;
2993 } else {
2994 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2995 changed = true;
2996 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002997
Johan Hedberged9b5f22012-02-21 20:47:06 +02002998 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002999 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003000
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003001 if (changed)
3002 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003003
3004 if (match.sk)
3005 sock_put(match.sk);
3006
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003007 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003008}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003009
Johan Hedberg744cf192011-11-08 20:40:14 +02003010int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003011{
Johan Hedbergca69b792011-11-11 18:10:00 +02003012 u8 mgmt_err = mgmt_status(status);
3013
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003014 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003015 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003016 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003017
3018 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003019 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003020 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003021
3022 return 0;
3023}
3024
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003025int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3026 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003027{
Johan Hedberg86742e12011-11-07 23:13:38 +02003028 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003029
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003030 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003031
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003032 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003033 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003034 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003035 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003036 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003037 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003038
Johan Hedberg744cf192011-11-08 20:40:14 +02003039 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003040}
Johan Hedbergf7520542011-01-20 12:34:39 +02003041
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003042int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3043{
3044 struct mgmt_ev_new_long_term_key ev;
3045
3046 memset(&ev, 0, sizeof(ev));
3047
3048 ev.store_hint = persistent;
3049 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003050 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003051 ev.key.authenticated = key->authenticated;
3052 ev.key.enc_size = key->enc_size;
3053 ev.key.ediv = key->ediv;
3054
3055 if (key->type == HCI_SMP_LTK)
3056 ev.key.master = 1;
3057
3058 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3059 memcpy(ev.key.val, key->val, sizeof(key->val));
3060
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003061 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3062 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003063}
3064
Johan Hedbergafc747a2012-01-15 18:11:07 +02003065int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003066 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3067 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003068{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003069 char buf[512];
3070 struct mgmt_ev_device_connected *ev = (void *) buf;
3071 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003072
Johan Hedbergb644ba32012-01-17 21:48:47 +02003073 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003074 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003075
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003076 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003077
Johan Hedbergb644ba32012-01-17 21:48:47 +02003078 if (name_len > 0)
3079 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003080 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003081
3082 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003083 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003084 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003085
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003086 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003087
3088 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003089 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003090}
3091
Johan Hedberg8962ee72011-01-20 12:40:27 +02003092static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3093{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003094 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003095 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003096 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003097
Johan Hedberg88c3df12012-02-09 14:27:38 +02003098 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3099 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003100
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003101 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003102 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003103
3104 *sk = cmd->sk;
3105 sock_hold(*sk);
3106
Johan Hedberga664b5b2011-02-19 12:06:02 -03003107 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003108}
3109
Johan Hedberg124f6e32012-02-09 13:50:12 +02003110static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003111{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003112 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003113 struct mgmt_cp_unpair_device *cp = cmd->param;
3114 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003115
3116 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003117 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3118 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003119
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003120 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3121
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003122 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003123
3124 mgmt_pending_remove(cmd);
3125}
3126
Johan Hedbergafc747a2012-01-15 18:11:07 +02003127int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003128 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003129{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003130 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003131 struct sock *sk = NULL;
3132 int err;
3133
Johan Hedberg744cf192011-11-08 20:40:14 +02003134 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003135
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003136 bacpy(&ev.addr.bdaddr, bdaddr);
3137 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3138 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003139
Johan Hedbergafc747a2012-01-15 18:11:07 +02003140 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003141 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003142
3143 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003144 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003145
Johan Hedberg124f6e32012-02-09 13:50:12 +02003146 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003147 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003148
Johan Hedberg8962ee72011-01-20 12:40:27 +02003149 return err;
3150}
3151
Johan Hedberg88c3df12012-02-09 14:27:38 +02003152int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003153 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003154{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003155 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003156 struct pending_cmd *cmd;
3157 int err;
3158
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003159 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3160 hdev);
3161
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003162 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003163 if (!cmd)
3164 return -ENOENT;
3165
Johan Hedberg88c3df12012-02-09 14:27:38 +02003166 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003167 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003168
Johan Hedberg88c3df12012-02-09 14:27:38 +02003169 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003170 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003171
Johan Hedberga664b5b2011-02-19 12:06:02 -03003172 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003173
3174 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003175}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003176
Johan Hedberg48264f02011-11-09 13:58:58 +02003177int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003178 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003179{
3180 struct mgmt_ev_connect_failed ev;
3181
Johan Hedberg4c659c32011-11-07 23:13:39 +02003182 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003183 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003184 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003185
Johan Hedberg744cf192011-11-08 20:40:14 +02003186 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003187}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003188
Johan Hedberg744cf192011-11-08 20:40:14 +02003189int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003190{
3191 struct mgmt_ev_pin_code_request ev;
3192
Johan Hedbergd8457692012-02-17 14:24:57 +02003193 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003194 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003195 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003196
Johan Hedberg744cf192011-11-08 20:40:14 +02003197 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003198 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003199}
3200
Johan Hedberg744cf192011-11-08 20:40:14 +02003201int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003202 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003203{
3204 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003205 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003206 int err;
3207
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003208 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003209 if (!cmd)
3210 return -ENOENT;
3211
Johan Hedbergd8457692012-02-17 14:24:57 +02003212 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003213 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003214
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003215 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003217
Johan Hedberga664b5b2011-02-19 12:06:02 -03003218 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003219
3220 return err;
3221}
3222
Johan Hedberg744cf192011-11-08 20:40:14 +02003223int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003224 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003225{
3226 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003227 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003228 int err;
3229
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003230 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003231 if (!cmd)
3232 return -ENOENT;
3233
Johan Hedbergd8457692012-02-17 14:24:57 +02003234 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003235 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003236
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003237 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003238 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003239
Johan Hedberga664b5b2011-02-19 12:06:02 -03003240 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003241
3242 return err;
3243}
Johan Hedberga5c29682011-02-19 12:05:57 -03003244
Johan Hedberg744cf192011-11-08 20:40:14 +02003245int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003246 u8 link_type, u8 addr_type, __le32 value,
3247 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003248{
3249 struct mgmt_ev_user_confirm_request ev;
3250
Johan Hedberg744cf192011-11-08 20:40:14 +02003251 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003252
Johan Hedberg272d90d2012-02-09 15:26:12 +02003253 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003254 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003255 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003256 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003257
Johan Hedberg744cf192011-11-08 20:40:14 +02003258 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003259 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003260}
3261
Johan Hedberg272d90d2012-02-09 15:26:12 +02003262int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003263 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003264{
3265 struct mgmt_ev_user_passkey_request ev;
3266
3267 BT_DBG("%s", hdev->name);
3268
Johan Hedberg272d90d2012-02-09 15:26:12 +02003269 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003270 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003271
3272 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003273 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003274}
3275
Brian Gix0df4c182011-11-16 13:53:13 -08003276static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003277 u8 link_type, u8 addr_type, u8 status,
3278 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003279{
3280 struct pending_cmd *cmd;
3281 struct mgmt_rp_user_confirm_reply rp;
3282 int err;
3283
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003284 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003285 if (!cmd)
3286 return -ENOENT;
3287
Johan Hedberg272d90d2012-02-09 15:26:12 +02003288 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003289 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003290 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003291 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003292
Johan Hedberga664b5b2011-02-19 12:06:02 -03003293 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003294
3295 return err;
3296}
3297
Johan Hedberg744cf192011-11-08 20:40:14 +02003298int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003299 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003300{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003301 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003302 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003303}
3304
Johan Hedberg272d90d2012-02-09 15:26:12 +02003305int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003306 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003307{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003308 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003309 status,
3310 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003311}
Johan Hedberg2a611692011-02-19 12:06:00 -03003312
Brian Gix604086b2011-11-23 08:28:33 -08003313int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003314 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003315{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003316 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003317 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003318}
3319
Johan Hedberg272d90d2012-02-09 15:26:12 +02003320int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003321 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003322{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003323 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003324 status,
3325 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003326}
3327
Johan Hedberg92a25252012-09-06 18:39:26 +03003328int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3329 u8 link_type, u8 addr_type, u32 passkey,
3330 u8 entered)
3331{
3332 struct mgmt_ev_passkey_notify ev;
3333
3334 BT_DBG("%s", hdev->name);
3335
3336 bacpy(&ev.addr.bdaddr, bdaddr);
3337 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3338 ev.passkey = __cpu_to_le32(passkey);
3339 ev.entered = entered;
3340
3341 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3342}
3343
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003344int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003345 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003346{
3347 struct mgmt_ev_auth_failed ev;
3348
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003349 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003350 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003351 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003352
Johan Hedberg744cf192011-11-08 20:40:14 +02003353 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003354}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003355
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003356int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3357{
3358 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003359 bool changed = false;
3360 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003361
3362 if (status) {
3363 u8 mgmt_err = mgmt_status(status);
3364 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003365 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003366 return 0;
3367 }
3368
Johan Hedberg47990ea2012-02-22 11:58:37 +02003369 if (test_bit(HCI_AUTH, &hdev->flags)) {
3370 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3371 changed = true;
3372 } else {
3373 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3374 changed = true;
3375 }
3376
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003377 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003378 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003379
Johan Hedberg47990ea2012-02-22 11:58:37 +02003380 if (changed)
3381 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003382
3383 if (match.sk)
3384 sock_put(match.sk);
3385
3386 return err;
3387}
3388
Johan Hedbergcacaf522012-02-21 00:52:42 +02003389static int clear_eir(struct hci_dev *hdev)
3390{
3391 struct hci_cp_write_eir cp;
3392
Johan Hedberg976eb202012-10-24 21:12:01 +03003393 if (!lmp_ext_inq_capable(hdev))
Johan Hedbergcacaf522012-02-21 00:52:42 +02003394 return 0;
3395
Johan Hedbergc80da272012-02-22 15:38:48 +02003396 memset(hdev->eir, 0, sizeof(hdev->eir));
3397
Johan Hedbergcacaf522012-02-21 00:52:42 +02003398 memset(&cp, 0, sizeof(cp));
3399
3400 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3401}
3402
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003403int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003404{
3405 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003406 bool changed = false;
3407 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003408
3409 if (status) {
3410 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003411
3412 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003413 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003414 err = new_settings(hdev, NULL);
3415
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003416 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3417 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003418
3419 return err;
3420 }
3421
3422 if (enable) {
3423 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3424 changed = true;
3425 } else {
3426 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3427 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003428 }
3429
3430 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3431
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003432 if (changed)
3433 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003434
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003435 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003436 sock_put(match.sk);
3437
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003438 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3439 update_eir(hdev);
3440 else
3441 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003442
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003443 return err;
3444}
3445
Johan Hedberg90e70452012-02-23 23:09:40 +02003446static void class_rsp(struct pending_cmd *cmd, void *data)
3447{
3448 struct cmd_lookup *match = data;
3449
3450 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003451 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003452
3453 list_del(&cmd->list);
3454
3455 if (match->sk == NULL) {
3456 match->sk = cmd->sk;
3457 sock_hold(match->sk);
3458 }
3459
3460 mgmt_pending_free(cmd);
3461}
3462
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003463int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003464 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003465{
Johan Hedberg90e70452012-02-23 23:09:40 +02003466 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3467 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003468
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003469 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3470
Johan Hedberg90e70452012-02-23 23:09:40 +02003471 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3472 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3473 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3474
3475 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003476 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3477 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003478
3479 if (match.sk)
3480 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003481
3482 return err;
3483}
3484
Johan Hedberg744cf192011-11-08 20:40:14 +02003485int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003486{
3487 struct pending_cmd *cmd;
3488 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003489 bool changed = false;
3490 int err = 0;
3491
3492 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3493 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3494 changed = true;
3495 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003496
3497 memset(&ev, 0, sizeof(ev));
3498 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003499 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003500
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003501 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003502 if (!cmd)
3503 goto send_event;
3504
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003505 /* Always assume that either the short or the complete name has
3506 * changed if there was a pending mgmt command */
3507 changed = true;
3508
Johan Hedbergb312b1612011-03-16 14:29:37 +02003509 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003510 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003511 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003512 goto failed;
3513 }
3514
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003515 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003516 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003517 if (err < 0)
3518 goto failed;
3519
3520send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003521 if (changed)
3522 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003523 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003524
Johan Hedberg1225a6b2012-10-25 00:09:54 +03003525 /* EIR is taken care of separately when powering on the
3526 * adapter so only update them here if this is a name change
3527 * unrelated to power on.
3528 */
3529 if (!test_bit(HCI_INIT, &hdev->flags))
3530 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003531
3532failed:
3533 if (cmd)
3534 mgmt_pending_remove(cmd);
3535 return err;
3536}
Szymon Jancc35938b2011-03-22 13:12:21 +01003537
Johan Hedberg744cf192011-11-08 20:40:14 +02003538int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003539 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003540{
3541 struct pending_cmd *cmd;
3542 int err;
3543
Johan Hedberg744cf192011-11-08 20:40:14 +02003544 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003546 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003547 if (!cmd)
3548 return -ENOENT;
3549
3550 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003551 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3552 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003553 } else {
3554 struct mgmt_rp_read_local_oob_data rp;
3555
3556 memcpy(rp.hash, hash, sizeof(rp.hash));
3557 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3558
Johan Hedberg744cf192011-11-08 20:40:14 +02003559 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003560 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3561 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003562 }
3563
3564 mgmt_pending_remove(cmd);
3565
3566 return err;
3567}
Johan Hedberge17acd42011-03-30 23:57:16 +03003568
Johan Hedberg06199cf2012-02-22 16:37:11 +02003569int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3570{
3571 struct cmd_lookup match = { NULL, hdev };
3572 bool changed = false;
3573 int err = 0;
3574
3575 if (status) {
3576 u8 mgmt_err = mgmt_status(status);
3577
3578 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003579 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003580 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003581
Szymon Jancd97dcb62012-03-16 16:02:56 +01003582 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3583 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003584
3585 return err;
3586 }
3587
3588 if (enable) {
3589 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3590 changed = true;
3591 } else {
3592 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3593 changed = true;
3594 }
3595
3596 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3597
3598 if (changed)
3599 err = new_settings(hdev, match.sk);
3600
3601 if (match.sk)
3602 sock_put(match.sk);
3603
3604 return err;
3605}
3606
Johan Hedberg48264f02011-11-09 13:58:58 +02003607int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003608 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3609 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003610{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003611 char buf[512];
3612 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003613 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003614
Johan Hedberg1dc06092012-01-15 21:01:23 +02003615 /* Leave 5 bytes for a potential CoD field */
3616 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003617 return -EINVAL;
3618
Johan Hedberg1dc06092012-01-15 21:01:23 +02003619 memset(buf, 0, sizeof(buf));
3620
Johan Hedberge319d2e2012-01-15 19:51:59 +02003621 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003622 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003623 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003624 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303625 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003626 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303627 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003628
Johan Hedberg1dc06092012-01-15 21:01:23 +02003629 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003630 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003631
Johan Hedberg1dc06092012-01-15 21:01:23 +02003632 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3633 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003634 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003635
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003636 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003637 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003638
Johan Hedberge319d2e2012-01-15 19:51:59 +02003639 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003640}
Johan Hedberga88a9652011-03-30 13:18:12 +03003641
Johan Hedbergb644ba32012-01-17 21:48:47 +02003642int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003643 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003644{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003645 struct mgmt_ev_device_found *ev;
3646 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3647 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003648
Johan Hedbergb644ba32012-01-17 21:48:47 +02003649 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003650
Johan Hedbergb644ba32012-01-17 21:48:47 +02003651 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003652
Johan Hedbergb644ba32012-01-17 21:48:47 +02003653 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003654 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003655 ev->rssi = rssi;
3656
3657 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003658 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003659
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003660 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003661
Johan Hedberg053c7e02012-02-04 00:06:00 +02003662 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003663 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003664}
Johan Hedberg314b2382011-04-27 10:29:57 -04003665
Andre Guedes7a135102011-11-09 17:14:25 -03003666int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003667{
3668 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003669 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003670 int err;
3671
Andre Guedes203159d2012-02-13 15:41:01 -03003672 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3673
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003674 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003675 if (!cmd)
3676 return -ENOENT;
3677
Johan Hedbergf808e162012-02-19 12:52:07 +02003678 type = hdev->discovery.type;
3679
3680 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003681 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003682 mgmt_pending_remove(cmd);
3683
3684 return err;
3685}
3686
Andre Guedese6d465c2011-11-09 17:14:26 -03003687int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3688{
3689 struct pending_cmd *cmd;
3690 int err;
3691
3692 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3693 if (!cmd)
3694 return -ENOENT;
3695
Johan Hedbergd9306502012-02-20 23:25:18 +02003696 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003697 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003698 mgmt_pending_remove(cmd);
3699
3700 return err;
3701}
Johan Hedberg314b2382011-04-27 10:29:57 -04003702
Johan Hedberg744cf192011-11-08 20:40:14 +02003703int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003704{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003705 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003706 struct pending_cmd *cmd;
3707
Andre Guedes343fb142011-11-22 17:14:19 -03003708 BT_DBG("%s discovering %u", hdev->name, discovering);
3709
Johan Hedberg164a6e72011-11-01 17:06:44 +02003710 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003711 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003712 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003713 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003714
3715 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003716 u8 type = hdev->discovery.type;
3717
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003718 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3719 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003720 mgmt_pending_remove(cmd);
3721 }
3722
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003723 memset(&ev, 0, sizeof(ev));
3724 ev.type = hdev->discovery.type;
3725 ev.discovering = discovering;
3726
3727 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003728}
Antti Julku5e762442011-08-25 16:48:02 +03003729
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003730int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003731{
3732 struct pending_cmd *cmd;
3733 struct mgmt_ev_device_blocked ev;
3734
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003735 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003736
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003737 bacpy(&ev.addr.bdaddr, bdaddr);
3738 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003739
Johan Hedberg744cf192011-11-08 20:40:14 +02003740 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003741 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003742}
3743
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003744int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003745{
3746 struct pending_cmd *cmd;
3747 struct mgmt_ev_device_unblocked ev;
3748
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003749 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003750
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003751 bacpy(&ev.addr.bdaddr, bdaddr);
3752 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003753
Johan Hedberg744cf192011-11-08 20:40:14 +02003754 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003755 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003756}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003757
3758module_param(enable_hs, bool, 0644);
3759MODULE_PARM_DESC(enable_hs, "Enable High Speed support");