blob: dd48e2a88c50d9f8614fdcf85e3cb0c4a6458328 [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
Johan Hedberg2da9c552012-02-17 14:39:28 +020035#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070036#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020037
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070076 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030077 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030078 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070079 MGMT_OP_SET_STATIC_ADDRESS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020080};
81
82static const u16 mgmt_events[] = {
83 MGMT_EV_CONTROLLER_ERROR,
84 MGMT_EV_INDEX_ADDED,
85 MGMT_EV_INDEX_REMOVED,
86 MGMT_EV_NEW_SETTINGS,
87 MGMT_EV_CLASS_OF_DEV_CHANGED,
88 MGMT_EV_LOCAL_NAME_CHANGED,
89 MGMT_EV_NEW_LINK_KEY,
90 MGMT_EV_NEW_LONG_TERM_KEY,
91 MGMT_EV_DEVICE_CONNECTED,
92 MGMT_EV_DEVICE_DISCONNECTED,
93 MGMT_EV_CONNECT_FAILED,
94 MGMT_EV_PIN_CODE_REQUEST,
95 MGMT_EV_USER_CONFIRM_REQUEST,
96 MGMT_EV_USER_PASSKEY_REQUEST,
97 MGMT_EV_AUTH_FAILED,
98 MGMT_EV_DEVICE_FOUND,
99 MGMT_EV_DISCOVERING,
100 MGMT_EV_DEVICE_BLOCKED,
101 MGMT_EV_DEVICE_UNBLOCKED,
102 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300103 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200104};
105
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800106#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200107
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200108#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
109 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
110
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200111struct pending_cmd {
112 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200113 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100115 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300117 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118};
119
Johan Hedbergca69b792011-11-11 18:10:00 +0200120/* HCI to MGMT error code conversion table */
121static u8 mgmt_status_table[] = {
122 MGMT_STATUS_SUCCESS,
123 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
124 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
125 MGMT_STATUS_FAILED, /* Hardware Failure */
126 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
127 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
128 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
129 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
130 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
132 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
133 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
134 MGMT_STATUS_BUSY, /* Command Disallowed */
135 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
136 MGMT_STATUS_REJECTED, /* Rejected Security */
137 MGMT_STATUS_REJECTED, /* Rejected Personal */
138 MGMT_STATUS_TIMEOUT, /* Host Timeout */
139 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
140 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
141 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
142 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
143 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
144 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
145 MGMT_STATUS_BUSY, /* Repeated Attempts */
146 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
147 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
148 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
149 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
150 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
151 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
153 MGMT_STATUS_FAILED, /* Unspecified Error */
154 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
155 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
156 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
157 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
158 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
159 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
160 MGMT_STATUS_FAILED, /* Unit Link Key Used */
161 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
162 MGMT_STATUS_TIMEOUT, /* Instant Passed */
163 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
164 MGMT_STATUS_FAILED, /* Transaction Collision */
165 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
166 MGMT_STATUS_REJECTED, /* QoS Rejected */
167 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
168 MGMT_STATUS_REJECTED, /* Insufficient Security */
169 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
170 MGMT_STATUS_BUSY, /* Role Switch Pending */
171 MGMT_STATUS_FAILED, /* Slot Violation */
172 MGMT_STATUS_FAILED, /* Role Switch Failed */
173 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
174 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
175 MGMT_STATUS_BUSY, /* Host Busy Pairing */
176 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
177 MGMT_STATUS_BUSY, /* Controller Busy */
178 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
179 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
180 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
181 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
182 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
183};
184
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300185bool mgmt_valid_hdev(struct hci_dev *hdev)
186{
187 return hdev->dev_type == HCI_BREDR;
188}
189
Johan Hedbergca69b792011-11-11 18:10:00 +0200190static u8 mgmt_status(u8 hci_status)
191{
192 if (hci_status < ARRAY_SIZE(mgmt_status_table))
193 return mgmt_status_table[hci_status];
194
195 return MGMT_STATUS_FAILED;
196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200199{
200 struct sk_buff *skb;
201 struct mgmt_hdr *hdr;
202 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300203 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204
Szymon Janc34eb5252011-02-28 14:10:08 +0100205 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Andre Guedes790eff42012-06-07 19:05:46 -0300207 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208 if (!skb)
209 return -ENOMEM;
210
211 hdr = (void *) skb_put(skb, sizeof(*hdr));
212
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530213 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100214 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215 hdr->len = cpu_to_le16(sizeof(*ev));
216
217 ev = (void *) skb_put(skb, sizeof(*ev));
218 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200219 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300221 err = sock_queue_rcv_skb(sk, skb);
222 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 kfree_skb(skb);
224
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300225 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226}
227
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200228static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300229 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200230{
231 struct sk_buff *skb;
232 struct mgmt_hdr *hdr;
233 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200235
236 BT_DBG("sock %p", sk);
237
Andre Guedes790eff42012-06-07 19:05:46 -0300238 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200239 if (!skb)
240 return -ENOMEM;
241
242 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200243
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530244 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100245 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
Johan Hedberga38528f2011-01-22 06:46:43 +0200248 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200249 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200250 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100251
252 if (rp)
253 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200254
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300255 err = sock_queue_rcv_skb(sk, skb);
256 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200257 kfree_skb(skb);
258
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100259 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200260}
261
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300262static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
263 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200264{
265 struct mgmt_rp_read_version rp;
266
267 BT_DBG("sock %p", sk);
268
269 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200270 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200271
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200272 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200274}
275
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300276static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
277 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200278{
279 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200280 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
281 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200282 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283 size_t rp_size;
284 int i, err;
285
286 BT_DBG("sock %p", sk);
287
288 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
289
290 rp = kmalloc(rp_size, GFP_KERNEL);
291 if (!rp)
292 return -ENOMEM;
293
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200294 rp->num_commands = __constant_cpu_to_le16(num_commands);
295 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296
297 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
298 put_unaligned_le16(mgmt_commands[i], opcode);
299
300 for (i = 0; i < num_events; i++, opcode++)
301 put_unaligned_le16(mgmt_events[i], opcode);
302
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200303 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300304 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305 kfree(rp);
306
307 return err;
308}
309
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300310static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
311 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200314 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200315 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300317 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318
319 BT_DBG("sock %p", sk);
320
321 read_lock(&hci_dev_list_lock);
322
323 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300324 list_for_each_entry(d, &hci_dev_list, list) {
325 if (!mgmt_valid_hdev(d))
326 continue;
327
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 count++;
329 }
330
Johan Hedberga38528f2011-01-22 06:46:43 +0200331 rp_len = sizeof(*rp) + (2 * count);
332 rp = kmalloc(rp_len, GFP_ATOMIC);
333 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100334 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200335 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100336 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200337
Johan Hedberg476e44c2012-10-19 20:10:46 +0300338 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200339 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200340 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200341 continue;
342
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700343 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
344 continue;
345
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300346 if (!mgmt_valid_hdev(d))
347 continue;
348
Johan Hedberg476e44c2012-10-19 20:10:46 +0300349 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 BT_DBG("Added hci%u", d->id);
351 }
352
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 rp->num_controllers = cpu_to_le16(count);
354 rp_len = sizeof(*rp) + (2 * count);
355
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356 read_unlock(&hci_dev_list_lock);
357
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200358 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300359 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
Johan Hedberga38528f2011-01-22 06:46:43 +0200361 kfree(rp);
362
363 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364}
365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200367{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200369
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200371 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200372
Andre Guedes9a1a1992012-07-24 15:03:48 -0300373 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200375
Andre Guedesed3fa312012-07-24 15:03:46 -0300376 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300377 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500378 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
379 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300380 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200381 settings |= MGMT_SETTING_BREDR;
382 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700384 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100385
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300386 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200387 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300388 settings |= MGMT_SETTING_ADVERTISING;
389 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500404 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
405 settings |= MGMT_SETTING_FAST_CONNECTABLE;
406
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200407 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_DISCOVERABLE;
409
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200410 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_PAIRABLE;
412
Johan Hedberg56f87902013-10-02 13:43:13 +0300413 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_BREDR;
415
Johan Hedberg06199cf2012-02-22 16:37:11 +0200416 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg47990ea2012-02-22 11:58:37 +0200419 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200422 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200424
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200425 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
426 settings |= MGMT_SETTING_HS;
427
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200428 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300429 settings |= MGMT_SETTING_ADVERTISING;
430
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200431 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200432}
433
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300434#define PNP_INFO_SVCLASS_ID 0x1200
435
Johan Hedberg213202e2013-01-27 00:31:33 +0200436static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
437{
438 u8 *ptr = data, *uuids_start = NULL;
439 struct bt_uuid *uuid;
440
441 if (len < 4)
442 return ptr;
443
444 list_for_each_entry(uuid, &hdev->uuids, list) {
445 u16 uuid16;
446
447 if (uuid->size != 16)
448 continue;
449
450 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
451 if (uuid16 < 0x1100)
452 continue;
453
454 if (uuid16 == PNP_INFO_SVCLASS_ID)
455 continue;
456
457 if (!uuids_start) {
458 uuids_start = ptr;
459 uuids_start[0] = 1;
460 uuids_start[1] = EIR_UUID16_ALL;
461 ptr += 2;
462 }
463
464 /* Stop if not enough space to put next UUID */
465 if ((ptr - data) + sizeof(u16) > len) {
466 uuids_start[1] = EIR_UUID16_SOME;
467 break;
468 }
469
470 *ptr++ = (uuid16 & 0x00ff);
471 *ptr++ = (uuid16 & 0xff00) >> 8;
472 uuids_start[0] += sizeof(uuid16);
473 }
474
475 return ptr;
476}
477
Johan Hedbergcdf19632013-01-27 00:31:34 +0200478static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
479{
480 u8 *ptr = data, *uuids_start = NULL;
481 struct bt_uuid *uuid;
482
483 if (len < 6)
484 return ptr;
485
486 list_for_each_entry(uuid, &hdev->uuids, list) {
487 if (uuid->size != 32)
488 continue;
489
490 if (!uuids_start) {
491 uuids_start = ptr;
492 uuids_start[0] = 1;
493 uuids_start[1] = EIR_UUID32_ALL;
494 ptr += 2;
495 }
496
497 /* Stop if not enough space to put next UUID */
498 if ((ptr - data) + sizeof(u32) > len) {
499 uuids_start[1] = EIR_UUID32_SOME;
500 break;
501 }
502
503 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
504 ptr += sizeof(u32);
505 uuids_start[0] += sizeof(u32);
506 }
507
508 return ptr;
509}
510
Johan Hedbergc00d5752013-01-27 00:31:35 +0200511static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
512{
513 u8 *ptr = data, *uuids_start = NULL;
514 struct bt_uuid *uuid;
515
516 if (len < 18)
517 return ptr;
518
519 list_for_each_entry(uuid, &hdev->uuids, list) {
520 if (uuid->size != 128)
521 continue;
522
523 if (!uuids_start) {
524 uuids_start = ptr;
525 uuids_start[0] = 1;
526 uuids_start[1] = EIR_UUID128_ALL;
527 ptr += 2;
528 }
529
530 /* Stop if not enough space to put next UUID */
531 if ((ptr - data) + 16 > len) {
532 uuids_start[1] = EIR_UUID128_SOME;
533 break;
534 }
535
536 memcpy(ptr, uuid->uuid, 16);
537 ptr += 16;
538 uuids_start[0] += 16;
539 }
540
541 return ptr;
542}
543
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300544static void create_eir(struct hci_dev *hdev, u8 *data)
545{
546 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547 size_t name_len;
548
549 name_len = strlen(hdev->dev_name);
550
551 if (name_len > 0) {
552 /* EIR Data type */
553 if (name_len > 48) {
554 name_len = 48;
555 ptr[1] = EIR_NAME_SHORT;
556 } else
557 ptr[1] = EIR_NAME_COMPLETE;
558
559 /* EIR Data length */
560 ptr[0] = name_len + 1;
561
562 memcpy(ptr + 2, hdev->dev_name, name_len);
563
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 ptr += (name_len + 2);
565 }
566
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100567 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700568 ptr[0] = 2;
569 ptr[1] = EIR_TX_POWER;
570 ptr[2] = (u8) hdev->inq_tx_power;
571
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700572 ptr += 3;
573 }
574
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700575 if (hdev->devid_source > 0) {
576 ptr[0] = 9;
577 ptr[1] = EIR_DEVICE_ID;
578
579 put_unaligned_le16(hdev->devid_source, ptr + 2);
580 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
581 put_unaligned_le16(hdev->devid_product, ptr + 6);
582 put_unaligned_le16(hdev->devid_version, ptr + 8);
583
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700584 ptr += 10;
585 }
586
Johan Hedberg213202e2013-01-27 00:31:33 +0200587 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200588 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200589 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300590}
591
Johan Hedberg890ea892013-03-15 17:06:52 -0500592static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300593{
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595 struct hci_cp_write_eir cp;
596
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200597 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500598 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200599
Johan Hedberg976eb202012-10-24 21:12:01 +0300600 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500601 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300602
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200603 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500604 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300605
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200606 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500607 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608
609 memset(&cp, 0, sizeof(cp));
610
611 create_eir(hdev, cp.data);
612
613 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500614 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300615
616 memcpy(hdev->eir, cp.data, sizeof(cp.data));
617
Johan Hedberg890ea892013-03-15 17:06:52 -0500618 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300619}
620
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621static u8 get_service_classes(struct hci_dev *hdev)
622{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300623 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624 u8 val = 0;
625
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300626 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628
629 return val;
630}
631
Johan Hedberg890ea892013-03-15 17:06:52 -0500632static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200633{
Johan Hedberg890ea892013-03-15 17:06:52 -0500634 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200635 u8 cod[3];
636
637 BT_DBG("%s", hdev->name);
638
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200639 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500640 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200641
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200642 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500643 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200644
645 cod[0] = hdev->minor_class;
646 cod[1] = hdev->major_class;
647 cod[2] = get_service_classes(hdev);
648
649 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500650 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200651
Johan Hedberg890ea892013-03-15 17:06:52 -0500652 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200653}
654
Johan Hedberg7d785252011-12-15 00:47:39 +0200655static void service_cache_off(struct work_struct *work)
656{
657 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300658 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500659 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200660
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200661 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200662 return;
663
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 hci_req_init(&req, hdev);
665
Johan Hedberg7d785252011-12-15 00:47:39 +0200666 hci_dev_lock(hdev);
667
Johan Hedberg890ea892013-03-15 17:06:52 -0500668 update_eir(&req);
669 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200670
671 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500672
673 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200674}
675
Johan Hedberg6a919082012-02-28 06:17:26 +0200676static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200677{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200678 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200679 return;
680
Johan Hedberg4f87da82012-03-02 19:55:56 +0200681 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200682
Johan Hedberg4f87da82012-03-02 19:55:56 +0200683 /* Non-mgmt controlled devices get this bit set
684 * implicitly so that pairing works for them, however
685 * for mgmt we require user-space to explicitly enable
686 * it
687 */
688 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200689}
690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200691static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200693{
694 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200696 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200697
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300698 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200699
Johan Hedberg03811012010-12-08 00:21:06 +0200700 memset(&rp, 0, sizeof(rp));
701
Johan Hedberg03811012010-12-08 00:21:06 +0200702 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200703
704 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200705 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200706
707 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
708 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
709
710 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200711
712 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200713 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300715 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200716
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200717 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300718 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200719}
720
721static void mgmt_pending_free(struct pending_cmd *cmd)
722{
723 sock_put(cmd->sk);
724 kfree(cmd->param);
725 kfree(cmd);
726}
727
728static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300729 struct hci_dev *hdev, void *data,
730 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200731{
732 struct pending_cmd *cmd;
733
Andre Guedes12b94562012-06-07 19:05:45 -0300734 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200735 if (!cmd)
736 return NULL;
737
738 cmd->opcode = opcode;
739 cmd->index = hdev->id;
740
Andre Guedes12b94562012-06-07 19:05:45 -0300741 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 if (!cmd->param) {
743 kfree(cmd);
744 return NULL;
745 }
746
747 if (data)
748 memcpy(cmd->param, data, len);
749
750 cmd->sk = sk;
751 sock_hold(sk);
752
753 list_add(&cmd->list, &hdev->mgmt_pending);
754
755 return cmd;
756}
757
758static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300759 void (*cb)(struct pending_cmd *cmd,
760 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300761 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200762{
Andre Guedesa3d09352013-02-01 11:21:30 -0300763 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Andre Guedesa3d09352013-02-01 11:21:30 -0300765 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200766 if (opcode > 0 && cmd->opcode != opcode)
767 continue;
768
769 cb(cmd, data);
770 }
771}
772
773static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
774{
775 struct pending_cmd *cmd;
776
777 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
778 if (cmd->opcode == opcode)
779 return cmd;
780 }
781
782 return NULL;
783}
784
785static void mgmt_pending_remove(struct pending_cmd *cmd)
786{
787 list_del(&cmd->list);
788 mgmt_pending_free(cmd);
789}
790
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200792{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200793 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200794
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200795 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200797}
798
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200799static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300800 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200801{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300802 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200803 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200804 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200806 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedberga7e80f22013-01-09 16:05:19 +0200808 if (cp->val != 0x00 && cp->val != 0x01)
809 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
810 MGMT_STATUS_INVALID_PARAMS);
811
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300812 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200813
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300814 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
815 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
816 MGMT_STATUS_BUSY);
817 goto failed;
818 }
819
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100820 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
821 cancel_delayed_work(&hdev->power_off);
822
823 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200824 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
825 data, len);
826 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100827 goto failed;
828 }
829 }
830
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200831 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200832 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200833 goto failed;
834 }
835
Johan Hedberg03811012010-12-08 00:21:06 +0200836 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
837 if (!cmd) {
838 err = -ENOMEM;
839 goto failed;
840 }
841
842 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200843 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200844 else
Johan Hedberg19202572013-01-14 22:33:51 +0200845 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200846
847 err = 0;
848
849failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300850 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200851 return err;
852}
853
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300854static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
855 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200856{
857 struct sk_buff *skb;
858 struct mgmt_hdr *hdr;
859
Andre Guedes790eff42012-06-07 19:05:46 -0300860 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200861 if (!skb)
862 return -ENOMEM;
863
864 hdr = (void *) skb_put(skb, sizeof(*hdr));
865 hdr->opcode = cpu_to_le16(event);
866 if (hdev)
867 hdr->index = cpu_to_le16(hdev->id);
868 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530869 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200870 hdr->len = cpu_to_le16(data_len);
871
872 if (data)
873 memcpy(skb_put(skb, data_len), data, data_len);
874
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100875 /* Time stamp */
876 __net_timestamp(skb);
877
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200878 hci_send_to_control(skb, skip_sk);
879 kfree_skb(skb);
880
881 return 0;
882}
883
884static int new_settings(struct hci_dev *hdev, struct sock *skip)
885{
886 __le32 ev;
887
888 ev = cpu_to_le32(get_current_settings(hdev));
889
890 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
891}
892
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300893struct cmd_lookup {
894 struct sock *sk;
895 struct hci_dev *hdev;
896 u8 mgmt_status;
897};
898
899static void settings_rsp(struct pending_cmd *cmd, void *data)
900{
901 struct cmd_lookup *match = data;
902
903 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
904
905 list_del(&cmd->list);
906
907 if (match->sk == NULL) {
908 match->sk = cmd->sk;
909 sock_hold(match->sk);
910 }
911
912 mgmt_pending_free(cmd);
913}
914
915static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
916{
917 u8 *status = data;
918
919 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
920 mgmt_pending_remove(cmd);
921}
922
Johan Hedberge6fe7982013-10-02 15:45:22 +0300923static u8 mgmt_bredr_support(struct hci_dev *hdev)
924{
925 if (!lmp_bredr_capable(hdev))
926 return MGMT_STATUS_NOT_SUPPORTED;
927 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
928 return MGMT_STATUS_REJECTED;
929 else
930 return MGMT_STATUS_SUCCESS;
931}
932
933static u8 mgmt_le_support(struct hci_dev *hdev)
934{
935 if (!lmp_le_capable(hdev))
936 return MGMT_STATUS_NOT_SUPPORTED;
937 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
938 return MGMT_STATUS_REJECTED;
939 else
940 return MGMT_STATUS_SUCCESS;
941}
942
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200943static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300944 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200945{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300946 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200947 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200948 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300949 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200950 int err;
951
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200952 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200953
Johan Hedberge6fe7982013-10-02 15:45:22 +0300954 status = mgmt_bredr_support(hdev);
955 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300956 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300957 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300958
Johan Hedberga7e80f22013-01-09 16:05:19 +0200959 if (cp->val != 0x00 && cp->val != 0x01)
960 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
961 MGMT_STATUS_INVALID_PARAMS);
962
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700963 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100964 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200965 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300966 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200967
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300968 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200969
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200971 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300972 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200973 goto failed;
974 }
975
976 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300977 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200978 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300979 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200980 goto failed;
981 }
982
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200983 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200984 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300985 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200986 goto failed;
987 }
988
989 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200990 bool changed = false;
991
992 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
993 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
994 changed = true;
995 }
996
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200997 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200998 if (err < 0)
999 goto failed;
1000
1001 if (changed)
1002 err = new_settings(hdev, sk);
1003
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001004 goto failed;
1005 }
1006
1007 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001008 if (hdev->discov_timeout > 0) {
1009 cancel_delayed_work(&hdev->discov_off);
1010 hdev->discov_timeout = 0;
1011 }
1012
1013 if (cp->val && timeout > 0) {
1014 hdev->discov_timeout = timeout;
1015 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1016 msecs_to_jiffies(hdev->discov_timeout * 1000));
1017 }
1018
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001019 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001020 goto failed;
1021 }
1022
1023 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1024 if (!cmd) {
1025 err = -ENOMEM;
1026 goto failed;
1027 }
1028
1029 scan = SCAN_PAGE;
1030
1031 if (cp->val)
1032 scan |= SCAN_INQUIRY;
1033 else
1034 cancel_delayed_work(&hdev->discov_off);
1035
1036 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1037 if (err < 0)
1038 mgmt_pending_remove(cmd);
1039
Johan Hedberg03811012010-12-08 00:21:06 +02001040 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001041 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001042
1043failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001044 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001045 return err;
1046}
1047
Johan Hedberg406d7802013-03-15 17:07:09 -05001048static void write_fast_connectable(struct hci_request *req, bool enable)
1049{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001050 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001051 struct hci_cp_write_page_scan_activity acp;
1052 u8 type;
1053
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001054 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1055 return;
1056
Johan Hedberg406d7802013-03-15 17:07:09 -05001057 if (enable) {
1058 type = PAGE_SCAN_TYPE_INTERLACED;
1059
1060 /* 160 msec page scan interval */
1061 acp.interval = __constant_cpu_to_le16(0x0100);
1062 } else {
1063 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1064
1065 /* default 1.28 sec page scan */
1066 acp.interval = __constant_cpu_to_le16(0x0800);
1067 }
1068
1069 acp.window = __constant_cpu_to_le16(0x0012);
1070
Johan Hedbergbd98b992013-03-15 17:07:13 -05001071 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1072 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1073 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1074 sizeof(acp), &acp);
1075
1076 if (hdev->page_scan_type != type)
1077 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001078}
1079
Johan Hedberg2b76f452013-03-15 17:07:04 -05001080static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1081{
1082 struct pending_cmd *cmd;
1083
1084 BT_DBG("status 0x%02x", status);
1085
1086 hci_dev_lock(hdev);
1087
1088 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1089 if (!cmd)
1090 goto unlock;
1091
1092 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1093
1094 mgmt_pending_remove(cmd);
1095
1096unlock:
1097 hci_dev_unlock(hdev);
1098}
1099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001100static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001101 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001102{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001103 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001104 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001105 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001106 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001107 int err;
1108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001110
Johan Hedberge6fe7982013-10-02 15:45:22 +03001111 status = mgmt_bredr_support(hdev);
1112 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001113 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001114 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001115
Johan Hedberga7e80f22013-01-09 16:05:19 +02001116 if (cp->val != 0x00 && cp->val != 0x01)
1117 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1118 MGMT_STATUS_INVALID_PARAMS);
1119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001120 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001121
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001122 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001123 bool changed = false;
1124
1125 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1126 changed = true;
1127
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001128 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001129 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001130 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001131 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1132 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1133 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001134
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001135 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001136 if (err < 0)
1137 goto failed;
1138
1139 if (changed)
1140 err = new_settings(hdev, sk);
1141
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001142 goto failed;
1143 }
1144
1145 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001146 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001149 goto failed;
1150 }
1151
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001152 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001153 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001154 goto failed;
1155 }
1156
1157 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1158 if (!cmd) {
1159 err = -ENOMEM;
1160 goto failed;
1161 }
1162
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001163 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001165 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166 scan = 0;
1167
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001168 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001169 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001170 cancel_delayed_work(&hdev->discov_off);
1171 }
1172
Johan Hedberg2b76f452013-03-15 17:07:04 -05001173 hci_req_init(&req, hdev);
1174
1175 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1176
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001177 /* If we're going from non-connectable to connectable or
1178 * vice-versa when fast connectable is enabled ensure that fast
1179 * connectable gets disabled. write_fast_connectable won't do
1180 * anything if the page scan parameters are already what they
1181 * should be.
1182 */
1183 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001184 write_fast_connectable(&req, false);
1185
Johan Hedberg2b76f452013-03-15 17:07:04 -05001186 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187 if (err < 0)
1188 mgmt_pending_remove(cmd);
1189
1190failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001191 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192 return err;
1193}
1194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001196 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001197{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001198 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001199 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001201 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202
Johan Hedberga7e80f22013-01-09 16:05:19 +02001203 if (cp->val != 0x00 && cp->val != 0x01)
1204 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1205 MGMT_STATUS_INVALID_PARAMS);
1206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001207 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001208
1209 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001210 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001212 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001214 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001215 if (err < 0)
1216 goto failed;
1217
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001218 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001219
1220failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001221 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001222 return err;
1223}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001224
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001225static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1226 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001227{
1228 struct mgmt_mode *cp = data;
1229 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001230 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001231 int err;
1232
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001233 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001234
Johan Hedberge6fe7982013-10-02 15:45:22 +03001235 status = mgmt_bredr_support(hdev);
1236 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001237 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001238 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001239
Johan Hedberga7e80f22013-01-09 16:05:19 +02001240 if (cp->val != 0x00 && cp->val != 0x01)
1241 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1242 MGMT_STATUS_INVALID_PARAMS);
1243
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001244 hci_dev_lock(hdev);
1245
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001246 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001247 bool changed = false;
1248
1249 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001250 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001251 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1252 changed = true;
1253 }
1254
1255 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1256 if (err < 0)
1257 goto failed;
1258
1259 if (changed)
1260 err = new_settings(hdev, sk);
1261
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001262 goto failed;
1263 }
1264
1265 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001266 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001267 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001268 goto failed;
1269 }
1270
1271 val = !!cp->val;
1272
1273 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1274 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1275 goto failed;
1276 }
1277
1278 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1279 if (!cmd) {
1280 err = -ENOMEM;
1281 goto failed;
1282 }
1283
1284 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1285 if (err < 0) {
1286 mgmt_pending_remove(cmd);
1287 goto failed;
1288 }
1289
1290failed:
1291 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001292 return err;
1293}
1294
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001295static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001296{
1297 struct mgmt_mode *cp = data;
1298 struct pending_cmd *cmd;
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001299 u8 val, status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001300 int err;
1301
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001302 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001303
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001304 status = mgmt_bredr_support(hdev);
1305 if (status)
1306 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1307
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001308 if (!lmp_ssp_capable(hdev))
1309 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1310 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001311
Johan Hedberga7e80f22013-01-09 16:05:19 +02001312 if (cp->val != 0x00 && cp->val != 0x01)
1313 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1314 MGMT_STATUS_INVALID_PARAMS);
1315
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001316 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001317
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001318 val = !!cp->val;
1319
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001320 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001321 bool changed = false;
1322
1323 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1324 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1325 changed = true;
1326 }
1327
1328 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1329 if (err < 0)
1330 goto failed;
1331
1332 if (changed)
1333 err = new_settings(hdev, sk);
1334
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001335 goto failed;
1336 }
1337
1338 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001339 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1340 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001341 goto failed;
1342 }
1343
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001344 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1345 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1346 goto failed;
1347 }
1348
1349 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1350 if (!cmd) {
1351 err = -ENOMEM;
1352 goto failed;
1353 }
1354
1355 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1356 if (err < 0) {
1357 mgmt_pending_remove(cmd);
1358 goto failed;
1359 }
1360
1361failed:
1362 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001363 return err;
1364}
1365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001366static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001367{
1368 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001369 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001370 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001371 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001373 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001374
Johan Hedberge6fe7982013-10-02 15:45:22 +03001375 status = mgmt_bredr_support(hdev);
1376 if (status)
1377 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001378
Johan Hedberga7e80f22013-01-09 16:05:19 +02001379 if (cp->val != 0x00 && cp->val != 0x01)
1380 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1381 MGMT_STATUS_INVALID_PARAMS);
1382
Marcel Holtmannee392692013-10-01 22:59:23 -07001383 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001384
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001385 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001386 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001387 } else {
1388 if (hdev_is_powered(hdev)) {
1389 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1390 MGMT_STATUS_REJECTED);
1391 goto unlock;
1392 }
1393
Marcel Holtmannee392692013-10-01 22:59:23 -07001394 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001395 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001396
1397 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1398 if (err < 0)
1399 goto unlock;
1400
1401 if (changed)
1402 err = new_settings(hdev, sk);
1403
1404unlock:
1405 hci_dev_unlock(hdev);
1406 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001407}
1408
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001409static void enable_advertising(struct hci_request *req)
1410{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001411 struct hci_dev *hdev = req->hdev;
1412 struct hci_cp_le_set_adv_param cp;
1413 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001414
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001415 memset(&cp, 0, sizeof(cp));
1416 cp.min_interval = __constant_cpu_to_le16(0x0800);
1417 cp.max_interval = __constant_cpu_to_le16(0x0800);
1418 cp.type = LE_ADV_IND;
1419 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1420 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1421 else
1422 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1423 cp.channel_map = 0x07;
1424
1425 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1426
1427 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001428}
1429
1430static void disable_advertising(struct hci_request *req)
1431{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001432 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001433
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001434 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001435}
1436
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001437static void le_enable_complete(struct hci_dev *hdev, u8 status)
1438{
1439 struct cmd_lookup match = { NULL, hdev };
1440
1441 if (status) {
1442 u8 mgmt_err = mgmt_status(status);
1443
1444 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1445 &mgmt_err);
1446 return;
1447 }
1448
1449 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1450
1451 new_settings(hdev, match.sk);
1452
1453 if (match.sk)
1454 sock_put(match.sk);
1455}
1456
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001457static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001458{
1459 struct mgmt_mode *cp = data;
1460 struct hci_cp_write_le_host_supported hci_cp;
1461 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001462 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001463 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001464 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001465
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001466 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001467
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001468 if (!lmp_le_capable(hdev))
1469 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1470 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001471
Johan Hedberga7e80f22013-01-09 16:05:19 +02001472 if (cp->val != 0x00 && cp->val != 0x01)
1473 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1474 MGMT_STATUS_INVALID_PARAMS);
1475
Johan Hedbergc73eee92013-04-19 18:35:21 +03001476 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001477 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001478 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1479 MGMT_STATUS_REJECTED);
1480
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001481 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001482
1483 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001484 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001485
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001486 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001487 bool changed = false;
1488
1489 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1490 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1491 changed = true;
1492 }
1493
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001494 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1495 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001496 changed = true;
1497 }
1498
Johan Hedberg06199cf2012-02-22 16:37:11 +02001499 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1500 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001501 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001502
1503 if (changed)
1504 err = new_settings(hdev, sk);
1505
Johan Hedberg1de028c2012-02-29 19:55:35 -08001506 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001507 }
1508
Johan Hedberg4375f102013-09-25 13:26:10 +03001509 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1510 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001511 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001512 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001513 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001514 }
1515
1516 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1517 if (!cmd) {
1518 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001519 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001520 }
1521
1522 memset(&hci_cp, 0, sizeof(hci_cp));
1523
1524 if (val) {
1525 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001526 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001527 }
1528
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001529 hci_req_init(&req, hdev);
1530
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001531 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1532 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001533
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001534 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1535 &hci_cp);
1536
1537 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301538 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001539 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001540
Johan Hedberg1de028c2012-02-29 19:55:35 -08001541unlock:
1542 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001543 return err;
1544}
1545
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001546/* This is a helper function to test for pending mgmt commands that can
1547 * cause CoD or EIR HCI commands. We can only allow one such pending
1548 * mgmt command at a time since otherwise we cannot easily track what
1549 * the current values are, will be, and based on that calculate if a new
1550 * HCI command needs to be sent and if yes with what value.
1551 */
1552static bool pending_eir_or_class(struct hci_dev *hdev)
1553{
1554 struct pending_cmd *cmd;
1555
1556 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1557 switch (cmd->opcode) {
1558 case MGMT_OP_ADD_UUID:
1559 case MGMT_OP_REMOVE_UUID:
1560 case MGMT_OP_SET_DEV_CLASS:
1561 case MGMT_OP_SET_POWERED:
1562 return true;
1563 }
1564 }
1565
1566 return false;
1567}
1568
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001569static const u8 bluetooth_base_uuid[] = {
1570 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1571 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1572};
1573
1574static u8 get_uuid_size(const u8 *uuid)
1575{
1576 u32 val;
1577
1578 if (memcmp(uuid, bluetooth_base_uuid, 12))
1579 return 128;
1580
1581 val = get_unaligned_le32(&uuid[12]);
1582 if (val > 0xffff)
1583 return 32;
1584
1585 return 16;
1586}
1587
Johan Hedberg92da6092013-03-15 17:06:55 -05001588static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1589{
1590 struct pending_cmd *cmd;
1591
1592 hci_dev_lock(hdev);
1593
1594 cmd = mgmt_pending_find(mgmt_op, hdev);
1595 if (!cmd)
1596 goto unlock;
1597
1598 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1599 hdev->dev_class, 3);
1600
1601 mgmt_pending_remove(cmd);
1602
1603unlock:
1604 hci_dev_unlock(hdev);
1605}
1606
1607static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1608{
1609 BT_DBG("status 0x%02x", status);
1610
1611 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1612}
1613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001614static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001615{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001616 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001617 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001618 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001619 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001620 int err;
1621
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001622 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001623
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001624 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001626 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001627 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001628 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001629 goto failed;
1630 }
1631
Andre Guedes92c4c202012-06-07 19:05:44 -03001632 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001633 if (!uuid) {
1634 err = -ENOMEM;
1635 goto failed;
1636 }
1637
1638 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001639 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001640 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001641
Johan Hedbergde66aa62013-01-27 00:31:27 +02001642 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001643
Johan Hedberg890ea892013-03-15 17:06:52 -05001644 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001645
Johan Hedberg890ea892013-03-15 17:06:52 -05001646 update_class(&req);
1647 update_eir(&req);
1648
Johan Hedberg92da6092013-03-15 17:06:55 -05001649 err = hci_req_run(&req, add_uuid_complete);
1650 if (err < 0) {
1651 if (err != -ENODATA)
1652 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001653
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001654 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001655 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001656 goto failed;
1657 }
1658
1659 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001660 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001661 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001662 goto failed;
1663 }
1664
1665 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001666
1667failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001668 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001669 return err;
1670}
1671
Johan Hedberg24b78d02012-02-23 23:24:30 +02001672static bool enable_service_cache(struct hci_dev *hdev)
1673{
1674 if (!hdev_is_powered(hdev))
1675 return false;
1676
1677 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001678 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1679 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001680 return true;
1681 }
1682
1683 return false;
1684}
1685
Johan Hedberg92da6092013-03-15 17:06:55 -05001686static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1687{
1688 BT_DBG("status 0x%02x", status);
1689
1690 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1691}
1692
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001693static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001694 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001695{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001696 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001697 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001698 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001699 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05001700 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001701 int err, found;
1702
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001703 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001704
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001705 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001706
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001707 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001708 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001709 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001710 goto unlock;
1711 }
1712
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001713 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1714 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001715
Johan Hedberg24b78d02012-02-23 23:24:30 +02001716 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001717 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001718 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001719 goto unlock;
1720 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001721
Johan Hedberg9246a862012-02-23 21:33:16 +02001722 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001723 }
1724
1725 found = 0;
1726
Johan Hedberg056341c2013-01-27 00:31:30 +02001727 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001728 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1729 continue;
1730
1731 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001732 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001733 found++;
1734 }
1735
1736 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001737 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001738 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001739 goto unlock;
1740 }
1741
Johan Hedberg9246a862012-02-23 21:33:16 +02001742update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001743 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001744
Johan Hedberg890ea892013-03-15 17:06:52 -05001745 update_class(&req);
1746 update_eir(&req);
1747
Johan Hedberg92da6092013-03-15 17:06:55 -05001748 err = hci_req_run(&req, remove_uuid_complete);
1749 if (err < 0) {
1750 if (err != -ENODATA)
1751 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001752
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001753 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001754 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001755 goto unlock;
1756 }
1757
1758 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001759 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001760 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001761 goto unlock;
1762 }
1763
1764 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001765
1766unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001767 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001768 return err;
1769}
1770
Johan Hedberg92da6092013-03-15 17:06:55 -05001771static void set_class_complete(struct hci_dev *hdev, u8 status)
1772{
1773 BT_DBG("status 0x%02x", status);
1774
1775 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1776}
1777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001778static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001779 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001780{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001781 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001782 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001783 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001784 int err;
1785
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001786 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001787
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001788 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001789 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1790 MGMT_STATUS_NOT_SUPPORTED);
1791
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001792 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001793
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001794 if (pending_eir_or_class(hdev)) {
1795 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1796 MGMT_STATUS_BUSY);
1797 goto unlock;
1798 }
1799
1800 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1801 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1802 MGMT_STATUS_INVALID_PARAMS);
1803 goto unlock;
1804 }
1805
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001806 hdev->major_class = cp->major;
1807 hdev->minor_class = cp->minor;
1808
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001809 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001810 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001811 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001812 goto unlock;
1813 }
1814
Johan Hedberg890ea892013-03-15 17:06:52 -05001815 hci_req_init(&req, hdev);
1816
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001817 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001818 hci_dev_unlock(hdev);
1819 cancel_delayed_work_sync(&hdev->service_cache);
1820 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001821 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001822 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001823
Johan Hedberg890ea892013-03-15 17:06:52 -05001824 update_class(&req);
1825
Johan Hedberg92da6092013-03-15 17:06:55 -05001826 err = hci_req_run(&req, set_class_complete);
1827 if (err < 0) {
1828 if (err != -ENODATA)
1829 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001830
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001831 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001832 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001833 goto unlock;
1834 }
1835
1836 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001837 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001838 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001839 goto unlock;
1840 }
1841
1842 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001843
Johan Hedbergb5235a62012-02-21 14:32:24 +02001844unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001845 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001846 return err;
1847}
1848
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001849static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001850 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001851{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001852 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001853 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001854 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001855
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001856 BT_DBG("request for %s", hdev->name);
1857
1858 if (!lmp_bredr_capable(hdev))
1859 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1860 MGMT_STATUS_NOT_SUPPORTED);
1861
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001862 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001863
Johan Hedberg86742e12011-11-07 23:13:38 +02001864 expected_len = sizeof(*cp) + key_count *
1865 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001866 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001867 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001868 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001869 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001870 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001871 }
1872
Johan Hedberg4ae14302013-01-20 14:27:13 +02001873 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1874 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1875 MGMT_STATUS_INVALID_PARAMS);
1876
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001877 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001878 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001880 for (i = 0; i < key_count; i++) {
1881 struct mgmt_link_key_info *key = &cp->keys[i];
1882
1883 if (key->addr.type != BDADDR_BREDR)
1884 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1885 MGMT_STATUS_INVALID_PARAMS);
1886 }
1887
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001888 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001889
1890 hci_link_keys_clear(hdev);
1891
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001892 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001893 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001894 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001895 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001896
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001897 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001898 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001899
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001900 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001901 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001902 }
1903
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001904 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001905
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001906 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001907
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001908 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001909}
1910
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001911static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001912 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001913{
1914 struct mgmt_ev_device_unpaired ev;
1915
1916 bacpy(&ev.addr.bdaddr, bdaddr);
1917 ev.addr.type = addr_type;
1918
1919 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001920 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001921}
1922
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001923static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001924 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001925{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001926 struct mgmt_cp_unpair_device *cp = data;
1927 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001928 struct hci_cp_disconnect dc;
1929 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001930 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001931 int err;
1932
Johan Hedberga8a1d192011-11-10 15:54:38 +02001933 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001934 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1935 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001936
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001937 if (!bdaddr_type_is_valid(cp->addr.type))
1938 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1939 MGMT_STATUS_INVALID_PARAMS,
1940 &rp, sizeof(rp));
1941
Johan Hedberg118da702013-01-20 14:27:20 +02001942 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1943 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1944 MGMT_STATUS_INVALID_PARAMS,
1945 &rp, sizeof(rp));
1946
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001947 hci_dev_lock(hdev);
1948
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001949 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001950 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001951 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001952 goto unlock;
1953 }
1954
Andre Guedes591f47f2012-04-24 21:02:49 -03001955 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001956 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1957 else
1958 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001959
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001960 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001961 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001962 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001963 goto unlock;
1964 }
1965
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001966 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001967 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001968 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001969 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001970 else
1971 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001972 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001973 } else {
1974 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001975 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001976
Johan Hedberga8a1d192011-11-10 15:54:38 +02001977 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001978 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001979 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001980 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001981 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001982 }
1983
Johan Hedberg124f6e32012-02-09 13:50:12 +02001984 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001985 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001986 if (!cmd) {
1987 err = -ENOMEM;
1988 goto unlock;
1989 }
1990
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001991 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001992 dc.reason = 0x13; /* Remote User Terminated Connection */
1993 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1994 if (err < 0)
1995 mgmt_pending_remove(cmd);
1996
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001997unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001998 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001999 return err;
2000}
2001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002002static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002003 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002004{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002005 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002006 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002007 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002008 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002009 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002010 int err;
2011
2012 BT_DBG("");
2013
Johan Hedberg06a63b12013-01-20 14:27:21 +02002014 memset(&rp, 0, sizeof(rp));
2015 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2016 rp.addr.type = cp->addr.type;
2017
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002018 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002019 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2020 MGMT_STATUS_INVALID_PARAMS,
2021 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002022
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002023 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002024
2025 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002026 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2027 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002028 goto failed;
2029 }
2030
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002031 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002032 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2033 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002034 goto failed;
2035 }
2036
Andre Guedes591f47f2012-04-24 21:02:49 -03002037 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002038 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2039 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002040 else
2041 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002042
Vishal Agarwalf9607272012-06-13 05:32:43 +05302043 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002044 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2045 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002046 goto failed;
2047 }
2048
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002049 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002050 if (!cmd) {
2051 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002052 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002053 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002054
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002055 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002056 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002057
2058 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2059 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002060 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002061
2062failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002063 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002064 return err;
2065}
2066
Andre Guedes57c14772012-04-24 21:02:50 -03002067static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002068{
2069 switch (link_type) {
2070 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002071 switch (addr_type) {
2072 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002073 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002074
Johan Hedberg48264f02011-11-09 13:58:58 +02002075 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002076 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002077 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002078 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002079
Johan Hedberg4c659c32011-11-07 23:13:39 +02002080 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002081 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002082 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002083 }
2084}
2085
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002086static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2087 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002088{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002089 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002090 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002091 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002092 int err;
2093 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002094
2095 BT_DBG("");
2096
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002097 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002098
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002099 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002100 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002101 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002102 goto unlock;
2103 }
2104
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002105 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002106 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2107 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002108 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002109 }
2110
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002111 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002112 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002113 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002114 err = -ENOMEM;
2115 goto unlock;
2116 }
2117
Johan Hedberg2784eb42011-01-21 13:56:35 +02002118 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002119 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002120 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2121 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002122 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002123 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002124 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002125 continue;
2126 i++;
2127 }
2128
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002129 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002130
Johan Hedberg4c659c32011-11-07 23:13:39 +02002131 /* Recalculate length in case of filtered SCO connections, etc */
2132 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002133
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002134 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002135 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002136
Johan Hedberga38528f2011-01-22 06:46:43 +02002137 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002138
2139unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002140 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002141 return err;
2142}
2143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002144static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002145 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002146{
2147 struct pending_cmd *cmd;
2148 int err;
2149
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002150 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002151 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002152 if (!cmd)
2153 return -ENOMEM;
2154
Johan Hedbergd8457692012-02-17 14:24:57 +02002155 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002156 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002157 if (err < 0)
2158 mgmt_pending_remove(cmd);
2159
2160 return err;
2161}
2162
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002163static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002164 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002165{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002166 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002167 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002168 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002169 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002170 int err;
2171
2172 BT_DBG("");
2173
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002175
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002176 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179 goto failed;
2180 }
2181
Johan Hedbergd8457692012-02-17 14:24:57 +02002182 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002183 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002184 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002185 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002186 goto failed;
2187 }
2188
2189 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002190 struct mgmt_cp_pin_code_neg_reply ncp;
2191
2192 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002193
2194 BT_ERR("PIN code is not 16 bytes long");
2195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002196 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002197 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002198 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002200
2201 goto failed;
2202 }
2203
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002204 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002205 if (!cmd) {
2206 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002207 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002208 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002209
Johan Hedbergd8457692012-02-17 14:24:57 +02002210 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002211 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002212 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002213
2214 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2215 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002216 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002217
2218failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002219 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002220 return err;
2221}
2222
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002223static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2224 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002225{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002226 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002227
2228 BT_DBG("");
2229
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002230 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002231
2232 hdev->io_capability = cp->io_capability;
2233
2234 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002235 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002236
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002237 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002238
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002239 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2240 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002241}
2242
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002243static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002244{
2245 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002246 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002247
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002248 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002249 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2250 continue;
2251
Johan Hedberge9a416b2011-02-19 12:05:56 -03002252 if (cmd->user_data != conn)
2253 continue;
2254
2255 return cmd;
2256 }
2257
2258 return NULL;
2259}
2260
2261static void pairing_complete(struct pending_cmd *cmd, u8 status)
2262{
2263 struct mgmt_rp_pair_device rp;
2264 struct hci_conn *conn = cmd->user_data;
2265
Johan Hedbergba4e5642011-11-11 00:07:34 +02002266 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002267 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002268
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002269 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002270 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002271
2272 /* So we don't get further callbacks for this connection */
2273 conn->connect_cfm_cb = NULL;
2274 conn->security_cfm_cb = NULL;
2275 conn->disconn_cfm_cb = NULL;
2276
David Herrmann76a68ba2013-04-06 20:28:37 +02002277 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002278
Johan Hedberga664b5b2011-02-19 12:06:02 -03002279 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002280}
2281
2282static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2283{
2284 struct pending_cmd *cmd;
2285
2286 BT_DBG("status %u", status);
2287
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002288 cmd = find_pairing(conn);
2289 if (!cmd)
2290 BT_DBG("Unable to find a pending command");
2291 else
Johan Hedberge2113262012-02-18 15:20:03 +02002292 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002293}
2294
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302295static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2296{
2297 struct pending_cmd *cmd;
2298
2299 BT_DBG("status %u", status);
2300
2301 if (!status)
2302 return;
2303
2304 cmd = find_pairing(conn);
2305 if (!cmd)
2306 BT_DBG("Unable to find a pending command");
2307 else
2308 pairing_complete(cmd, mgmt_status(status));
2309}
2310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002311static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002312 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002313{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002314 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002315 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002316 struct pending_cmd *cmd;
2317 u8 sec_level, auth_type;
2318 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002319 int err;
2320
2321 BT_DBG("");
2322
Szymon Jancf950a30e2013-01-18 12:48:07 +01002323 memset(&rp, 0, sizeof(rp));
2324 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2325 rp.addr.type = cp->addr.type;
2326
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002327 if (!bdaddr_type_is_valid(cp->addr.type))
2328 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2329 MGMT_STATUS_INVALID_PARAMS,
2330 &rp, sizeof(rp));
2331
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002332 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002333
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002334 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002335 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2336 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002337 goto unlock;
2338 }
2339
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002340 sec_level = BT_SECURITY_MEDIUM;
2341 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002342 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002343 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002344 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002345
Andre Guedes591f47f2012-04-24 21:02:49 -03002346 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002347 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2348 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002349 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002350 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2351 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002352
Ville Tervo30e76272011-02-22 16:10:53 -03002353 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002354 int status;
2355
2356 if (PTR_ERR(conn) == -EBUSY)
2357 status = MGMT_STATUS_BUSY;
2358 else
2359 status = MGMT_STATUS_CONNECT_FAILED;
2360
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002361 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002362 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002363 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002364 goto unlock;
2365 }
2366
2367 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002368 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002369 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002370 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002371 goto unlock;
2372 }
2373
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002374 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002375 if (!cmd) {
2376 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002377 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002378 goto unlock;
2379 }
2380
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002381 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002382 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002383 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302384 else
2385 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002386
Johan Hedberge9a416b2011-02-19 12:05:56 -03002387 conn->security_cfm_cb = pairing_complete_cb;
2388 conn->disconn_cfm_cb = pairing_complete_cb;
2389 conn->io_capability = cp->io_cap;
2390 cmd->user_data = conn;
2391
2392 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002393 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002394 pairing_complete(cmd, 0);
2395
2396 err = 0;
2397
2398unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002399 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002400 return err;
2401}
2402
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002403static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2404 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002405{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002406 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002407 struct pending_cmd *cmd;
2408 struct hci_conn *conn;
2409 int err;
2410
2411 BT_DBG("");
2412
Johan Hedberg28424702012-02-02 04:02:29 +02002413 hci_dev_lock(hdev);
2414
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002415 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002416 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002417 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002418 goto unlock;
2419 }
2420
Johan Hedberg28424702012-02-02 04:02:29 +02002421 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2422 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002423 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002425 goto unlock;
2426 }
2427
2428 conn = cmd->user_data;
2429
2430 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002431 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002432 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002433 goto unlock;
2434 }
2435
2436 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2437
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002438 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002439 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002440unlock:
2441 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002442 return err;
2443}
2444
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002445static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002446 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002447 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002448{
Johan Hedberga5c29682011-02-19 12:05:57 -03002449 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002450 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002451 int err;
2452
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002453 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002454
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002455 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002456 err = cmd_complete(sk, hdev->id, mgmt_op,
2457 MGMT_STATUS_NOT_POWERED, addr,
2458 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002459 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002460 }
2461
Johan Hedberg1707c602013-03-15 17:07:15 -05002462 if (addr->type == BDADDR_BREDR)
2463 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002464 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002465 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002466
Johan Hedberg272d90d2012-02-09 15:26:12 +02002467 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002468 err = cmd_complete(sk, hdev->id, mgmt_op,
2469 MGMT_STATUS_NOT_CONNECTED, addr,
2470 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002471 goto done;
2472 }
2473
Johan Hedberg1707c602013-03-15 17:07:15 -05002474 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002475 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002476 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002477
Brian Gix5fe57d92011-12-21 16:12:13 -08002478 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002479 err = cmd_complete(sk, hdev->id, mgmt_op,
2480 MGMT_STATUS_SUCCESS, addr,
2481 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002482 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002483 err = cmd_complete(sk, hdev->id, mgmt_op,
2484 MGMT_STATUS_FAILED, addr,
2485 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002486
Brian Gix47c15e22011-11-16 13:53:14 -08002487 goto done;
2488 }
2489
Johan Hedberg1707c602013-03-15 17:07:15 -05002490 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002491 if (!cmd) {
2492 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002493 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002494 }
2495
Brian Gix0df4c182011-11-16 13:53:13 -08002496 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002497 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2498 struct hci_cp_user_passkey_reply cp;
2499
Johan Hedberg1707c602013-03-15 17:07:15 -05002500 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002501 cp.passkey = passkey;
2502 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2503 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002504 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2505 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002506
Johan Hedberga664b5b2011-02-19 12:06:02 -03002507 if (err < 0)
2508 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002509
Brian Gix0df4c182011-11-16 13:53:13 -08002510done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002511 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002512 return err;
2513}
2514
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302515static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2516 void *data, u16 len)
2517{
2518 struct mgmt_cp_pin_code_neg_reply *cp = data;
2519
2520 BT_DBG("");
2521
Johan Hedberg1707c602013-03-15 17:07:15 -05002522 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302523 MGMT_OP_PIN_CODE_NEG_REPLY,
2524 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2525}
2526
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002527static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2528 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002529{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002530 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002531
2532 BT_DBG("");
2533
2534 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002535 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002537
Johan Hedberg1707c602013-03-15 17:07:15 -05002538 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 MGMT_OP_USER_CONFIRM_REPLY,
2540 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002541}
2542
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002543static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002544 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002545{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002546 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002547
2548 BT_DBG("");
2549
Johan Hedberg1707c602013-03-15 17:07:15 -05002550 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002551 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2552 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002553}
2554
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2556 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002557{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002558 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002559
2560 BT_DBG("");
2561
Johan Hedberg1707c602013-03-15 17:07:15 -05002562 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002563 MGMT_OP_USER_PASSKEY_REPLY,
2564 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002565}
2566
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002567static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002568 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002569{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002570 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002571
2572 BT_DBG("");
2573
Johan Hedberg1707c602013-03-15 17:07:15 -05002574 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002575 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2576 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002577}
2578
Johan Hedberg13928972013-03-15 17:07:00 -05002579static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002580{
Johan Hedberg13928972013-03-15 17:07:00 -05002581 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002582 struct hci_cp_write_local_name cp;
2583
Johan Hedberg13928972013-03-15 17:07:00 -05002584 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002585
Johan Hedberg890ea892013-03-15 17:06:52 -05002586 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002587}
2588
Johan Hedberg13928972013-03-15 17:07:00 -05002589static void set_name_complete(struct hci_dev *hdev, u8 status)
2590{
2591 struct mgmt_cp_set_local_name *cp;
2592 struct pending_cmd *cmd;
2593
2594 BT_DBG("status 0x%02x", status);
2595
2596 hci_dev_lock(hdev);
2597
2598 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2599 if (!cmd)
2600 goto unlock;
2601
2602 cp = cmd->param;
2603
2604 if (status)
2605 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2606 mgmt_status(status));
2607 else
2608 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2609 cp, sizeof(*cp));
2610
2611 mgmt_pending_remove(cmd);
2612
2613unlock:
2614 hci_dev_unlock(hdev);
2615}
2616
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002617static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002618 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002619{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002620 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002621 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002622 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002623 int err;
2624
2625 BT_DBG("");
2626
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002627 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002628
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002629 /* If the old values are the same as the new ones just return a
2630 * direct command complete event.
2631 */
2632 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2633 !memcmp(hdev->short_name, cp->short_name,
2634 sizeof(hdev->short_name))) {
2635 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2636 data, len);
2637 goto failed;
2638 }
2639
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002640 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002641
Johan Hedbergb5235a62012-02-21 14:32:24 +02002642 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002643 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002644
2645 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002646 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002647 if (err < 0)
2648 goto failed;
2649
2650 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002651 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002652
Johan Hedbergb5235a62012-02-21 14:32:24 +02002653 goto failed;
2654 }
2655
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002656 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002657 if (!cmd) {
2658 err = -ENOMEM;
2659 goto failed;
2660 }
2661
Johan Hedberg13928972013-03-15 17:07:00 -05002662 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2663
Johan Hedberg890ea892013-03-15 17:06:52 -05002664 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002665
2666 if (lmp_bredr_capable(hdev)) {
2667 update_name(&req);
2668 update_eir(&req);
2669 }
2670
2671 if (lmp_le_capable(hdev))
2672 hci_update_ad(&req);
2673
Johan Hedberg13928972013-03-15 17:07:00 -05002674 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002675 if (err < 0)
2676 mgmt_pending_remove(cmd);
2677
2678failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002679 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002680 return err;
2681}
2682
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002683static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002684 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002685{
Szymon Jancc35938b2011-03-22 13:12:21 +01002686 struct pending_cmd *cmd;
2687 int err;
2688
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002689 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002690
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002691 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002692
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002693 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002694 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002695 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002696 goto unlock;
2697 }
2698
Andre Guedes9a1a1992012-07-24 15:03:48 -03002699 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002700 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002701 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002702 goto unlock;
2703 }
2704
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002705 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002706 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002707 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002708 goto unlock;
2709 }
2710
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002711 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002712 if (!cmd) {
2713 err = -ENOMEM;
2714 goto unlock;
2715 }
2716
2717 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2718 if (err < 0)
2719 mgmt_pending_remove(cmd);
2720
2721unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002722 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002723 return err;
2724}
2725
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002726static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002727 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002728{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002729 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002730 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002731 int err;
2732
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002733 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002734
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002735 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002736
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002737 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002738 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002739 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002740 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002741 else
Szymon Janca6785be2012-12-13 15:11:21 +01002742 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002743
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002744 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002745 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002746
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002747 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002748 return err;
2749}
2750
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002751static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002752 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002753{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002754 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002755 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002756 int err;
2757
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002758 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002759
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002760 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002761
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002762 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002763 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002764 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002765 else
Szymon Janca6785be2012-12-13 15:11:21 +01002766 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002767
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002768 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002769 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002770
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002771 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002772 return err;
2773}
2774
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002775static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2776{
2777 struct pending_cmd *cmd;
2778 u8 type;
2779 int err;
2780
2781 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2782
2783 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2784 if (!cmd)
2785 return -ENOENT;
2786
2787 type = hdev->discovery.type;
2788
2789 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2790 &type, sizeof(type));
2791 mgmt_pending_remove(cmd);
2792
2793 return err;
2794}
2795
Andre Guedes7c307722013-04-30 15:29:28 -03002796static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2797{
2798 BT_DBG("status %d", status);
2799
2800 if (status) {
2801 hci_dev_lock(hdev);
2802 mgmt_start_discovery_failed(hdev, status);
2803 hci_dev_unlock(hdev);
2804 return;
2805 }
2806
2807 hci_dev_lock(hdev);
2808 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2809 hci_dev_unlock(hdev);
2810
2811 switch (hdev->discovery.type) {
2812 case DISCOV_TYPE_LE:
2813 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002814 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002815 break;
2816
2817 case DISCOV_TYPE_INTERLEAVED:
2818 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002819 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002820 break;
2821
2822 case DISCOV_TYPE_BREDR:
2823 break;
2824
2825 default:
2826 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2827 }
2828}
2829
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002830static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002831 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002832{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002833 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002834 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002835 struct hci_cp_le_set_scan_param param_cp;
2836 struct hci_cp_le_set_scan_enable enable_cp;
2837 struct hci_cp_inquiry inq_cp;
2838 struct hci_request req;
2839 /* General inquiry access code (GIAC) */
2840 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002841 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002842 int err;
2843
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002844 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002845
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002846 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002847
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002848 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002849 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002850 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002851 goto failed;
2852 }
2853
Andre Guedes642be6c2012-03-21 00:03:37 -03002854 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2855 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2856 MGMT_STATUS_BUSY);
2857 goto failed;
2858 }
2859
Johan Hedbergff9ef572012-01-04 14:23:45 +02002860 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002861 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002862 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002863 goto failed;
2864 }
2865
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002866 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002867 if (!cmd) {
2868 err = -ENOMEM;
2869 goto failed;
2870 }
2871
Andre Guedes4aab14e2012-02-17 20:39:36 -03002872 hdev->discovery.type = cp->type;
2873
Andre Guedes7c307722013-04-30 15:29:28 -03002874 hci_req_init(&req, hdev);
2875
Andre Guedes4aab14e2012-02-17 20:39:36 -03002876 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002877 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002878 status = mgmt_bredr_support(hdev);
2879 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002880 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002881 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002882 mgmt_pending_remove(cmd);
2883 goto failed;
2884 }
2885
Andre Guedes7c307722013-04-30 15:29:28 -03002886 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2887 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2888 MGMT_STATUS_BUSY);
2889 mgmt_pending_remove(cmd);
2890 goto failed;
2891 }
2892
2893 hci_inquiry_cache_flush(hdev);
2894
2895 memset(&inq_cp, 0, sizeof(inq_cp));
2896 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002897 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002898 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002899 break;
2900
2901 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002902 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002903 status = mgmt_le_support(hdev);
2904 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002905 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002906 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002907 mgmt_pending_remove(cmd);
2908 goto failed;
2909 }
2910
Andre Guedes7c307722013-04-30 15:29:28 -03002911 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002912 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002913 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2914 MGMT_STATUS_NOT_SUPPORTED);
2915 mgmt_pending_remove(cmd);
2916 goto failed;
2917 }
2918
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002919 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002920 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2921 MGMT_STATUS_REJECTED);
2922 mgmt_pending_remove(cmd);
2923 goto failed;
2924 }
2925
2926 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2927 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2928 MGMT_STATUS_BUSY);
2929 mgmt_pending_remove(cmd);
2930 goto failed;
2931 }
2932
2933 memset(&param_cp, 0, sizeof(param_cp));
2934 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002935 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2936 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002937 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2938 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2939 else
2940 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002941 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2942 &param_cp);
2943
2944 memset(&enable_cp, 0, sizeof(enable_cp));
2945 enable_cp.enable = LE_SCAN_ENABLE;
2946 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2947 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2948 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002949 break;
2950
Andre Guedesf39799f2012-02-17 20:39:35 -03002951 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002952 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2953 MGMT_STATUS_INVALID_PARAMS);
2954 mgmt_pending_remove(cmd);
2955 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002956 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002957
Andre Guedes7c307722013-04-30 15:29:28 -03002958 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002959 if (err < 0)
2960 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002961 else
2962 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002963
2964failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002965 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002966 return err;
2967}
2968
Andre Guedes1183fdc2013-04-30 15:29:35 -03002969static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2970{
2971 struct pending_cmd *cmd;
2972 int err;
2973
2974 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2975 if (!cmd)
2976 return -ENOENT;
2977
2978 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2979 &hdev->discovery.type, sizeof(hdev->discovery.type));
2980 mgmt_pending_remove(cmd);
2981
2982 return err;
2983}
2984
Andre Guedes0e05bba2013-04-30 15:29:33 -03002985static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2986{
2987 BT_DBG("status %d", status);
2988
2989 hci_dev_lock(hdev);
2990
2991 if (status) {
2992 mgmt_stop_discovery_failed(hdev, status);
2993 goto unlock;
2994 }
2995
2996 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2997
2998unlock:
2999 hci_dev_unlock(hdev);
3000}
3001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003002static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003003 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003004{
Johan Hedbergd9306502012-02-20 23:25:18 +02003005 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003006 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003007 struct hci_cp_remote_name_req_cancel cp;
3008 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003009 struct hci_request req;
3010 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003011 int err;
3012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003013 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003015 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003016
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003017 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003018 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003019 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3020 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003021 goto unlock;
3022 }
3023
3024 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003025 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003026 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3027 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003028 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003029 }
3030
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003031 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003032 if (!cmd) {
3033 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003034 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003035 }
3036
Andre Guedes0e05bba2013-04-30 15:29:33 -03003037 hci_req_init(&req, hdev);
3038
Andre Guedese0d9727e2012-03-20 15:15:36 -03003039 switch (hdev->discovery.state) {
3040 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003041 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3042 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3043 } else {
3044 cancel_delayed_work(&hdev->le_scan_disable);
3045
3046 memset(&enable_cp, 0, sizeof(enable_cp));
3047 enable_cp.enable = LE_SCAN_DISABLE;
3048 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3049 sizeof(enable_cp), &enable_cp);
3050 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003051
Andre Guedese0d9727e2012-03-20 15:15:36 -03003052 break;
3053
3054 case DISCOVERY_RESOLVING:
3055 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003056 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003057 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003058 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003059 err = cmd_complete(sk, hdev->id,
3060 MGMT_OP_STOP_DISCOVERY, 0,
3061 &mgmt_cp->type,
3062 sizeof(mgmt_cp->type));
3063 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3064 goto unlock;
3065 }
3066
3067 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003068 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3069 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003070
3071 break;
3072
3073 default:
3074 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003075
3076 mgmt_pending_remove(cmd);
3077 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3078 MGMT_STATUS_FAILED, &mgmt_cp->type,
3079 sizeof(mgmt_cp->type));
3080 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003081 }
3082
Andre Guedes0e05bba2013-04-30 15:29:33 -03003083 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003084 if (err < 0)
3085 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003086 else
3087 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003088
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003089unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003090 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003091 return err;
3092}
3093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003094static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003095 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003096{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003097 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003098 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003099 int err;
3100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003101 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003102
Johan Hedberg561aafb2012-01-04 13:31:59 +02003103 hci_dev_lock(hdev);
3104
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003105 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003106 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003107 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003108 goto failed;
3109 }
3110
Johan Hedberga198e7b2012-02-17 14:27:06 +02003111 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003112 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003113 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003114 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003115 goto failed;
3116 }
3117
3118 if (cp->name_known) {
3119 e->name_state = NAME_KNOWN;
3120 list_del(&e->list);
3121 } else {
3122 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003123 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003124 }
3125
Johan Hedberge3846622013-01-09 15:29:33 +02003126 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3127 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003128
3129failed:
3130 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003131 return err;
3132}
3133
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003134static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003135 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003136{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003137 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003138 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003139 int err;
3140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003141 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003142
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003143 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003144 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3145 MGMT_STATUS_INVALID_PARAMS,
3146 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003147
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003148 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003149
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003150 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003151 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003152 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003153 else
Szymon Janca6785be2012-12-13 15:11:21 +01003154 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003156 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003157 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003159 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003160
3161 return err;
3162}
3163
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003164static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003166{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003167 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003168 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003169 int err;
3170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003171 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003172
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003173 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003174 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3175 MGMT_STATUS_INVALID_PARAMS,
3176 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003177
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003178 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003179
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003180 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003181 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003182 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003183 else
Szymon Janca6785be2012-12-13 15:11:21 +01003184 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003185
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003186 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003187 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003188
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003189 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003190
3191 return err;
3192}
3193
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003194static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3195 u16 len)
3196{
3197 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003198 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003199 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003200 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003201
3202 BT_DBG("%s", hdev->name);
3203
Szymon Jancc72d4b82012-03-16 16:02:57 +01003204 source = __le16_to_cpu(cp->source);
3205
3206 if (source > 0x0002)
3207 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3208 MGMT_STATUS_INVALID_PARAMS);
3209
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003210 hci_dev_lock(hdev);
3211
Szymon Jancc72d4b82012-03-16 16:02:57 +01003212 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003213 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3214 hdev->devid_product = __le16_to_cpu(cp->product);
3215 hdev->devid_version = __le16_to_cpu(cp->version);
3216
3217 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3218
Johan Hedberg890ea892013-03-15 17:06:52 -05003219 hci_req_init(&req, hdev);
3220 update_eir(&req);
3221 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003222
3223 hci_dev_unlock(hdev);
3224
3225 return err;
3226}
3227
Johan Hedberg4375f102013-09-25 13:26:10 +03003228static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3229{
3230 struct cmd_lookup match = { NULL, hdev };
3231
3232 if (status) {
3233 u8 mgmt_err = mgmt_status(status);
3234
3235 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3236 cmd_status_rsp, &mgmt_err);
3237 return;
3238 }
3239
3240 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3241 &match);
3242
3243 new_settings(hdev, match.sk);
3244
3245 if (match.sk)
3246 sock_put(match.sk);
3247}
3248
3249static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3250{
3251 struct mgmt_mode *cp = data;
3252 struct pending_cmd *cmd;
3253 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003254 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003255 int err;
3256
3257 BT_DBG("request for %s", hdev->name);
3258
Johan Hedberge6fe7982013-10-02 15:45:22 +03003259 status = mgmt_le_support(hdev);
3260 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003261 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003262 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003263
3264 if (cp->val != 0x00 && cp->val != 0x01)
3265 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3266 MGMT_STATUS_INVALID_PARAMS);
3267
3268 hci_dev_lock(hdev);
3269
3270 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003271 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003272
3273 if (!hdev_is_powered(hdev) || val == enabled) {
3274 bool changed = false;
3275
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003276 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3277 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003278 changed = true;
3279 }
3280
3281 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3282 if (err < 0)
3283 goto unlock;
3284
3285 if (changed)
3286 err = new_settings(hdev, sk);
3287
3288 goto unlock;
3289 }
3290
3291 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3292 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3293 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3294 MGMT_STATUS_BUSY);
3295 goto unlock;
3296 }
3297
3298 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3299 if (!cmd) {
3300 err = -ENOMEM;
3301 goto unlock;
3302 }
3303
3304 hci_req_init(&req, hdev);
3305
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003306 if (val)
3307 enable_advertising(&req);
3308 else
3309 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003310
3311 err = hci_req_run(&req, set_advertising_complete);
3312 if (err < 0)
3313 mgmt_pending_remove(cmd);
3314
3315unlock:
3316 hci_dev_unlock(hdev);
3317 return err;
3318}
3319
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003320static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3321 void *data, u16 len)
3322{
3323 struct mgmt_cp_set_static_address *cp = data;
3324 int err;
3325
3326 BT_DBG("%s", hdev->name);
3327
Marcel Holtmann62af4442013-10-02 22:10:32 -07003328 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003329 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003330 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003331
3332 if (hdev_is_powered(hdev))
3333 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3334 MGMT_STATUS_REJECTED);
3335
3336 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3337 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3338 return cmd_status(sk, hdev->id,
3339 MGMT_OP_SET_STATIC_ADDRESS,
3340 MGMT_STATUS_INVALID_PARAMS);
3341
3342 /* Two most significant bits shall be set */
3343 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3344 return cmd_status(sk, hdev->id,
3345 MGMT_OP_SET_STATIC_ADDRESS,
3346 MGMT_STATUS_INVALID_PARAMS);
3347 }
3348
3349 hci_dev_lock(hdev);
3350
3351 bacpy(&hdev->static_addr, &cp->bdaddr);
3352
3353 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3354
3355 hci_dev_unlock(hdev);
3356
3357 return err;
3358}
3359
Johan Hedberg33e38b32013-03-15 17:07:05 -05003360static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3361{
3362 struct pending_cmd *cmd;
3363
3364 BT_DBG("status 0x%02x", status);
3365
3366 hci_dev_lock(hdev);
3367
3368 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3369 if (!cmd)
3370 goto unlock;
3371
3372 if (status) {
3373 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3374 mgmt_status(status));
3375 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003376 struct mgmt_mode *cp = cmd->param;
3377
3378 if (cp->val)
3379 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3380 else
3381 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3382
Johan Hedberg33e38b32013-03-15 17:07:05 -05003383 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3384 new_settings(hdev, cmd->sk);
3385 }
3386
3387 mgmt_pending_remove(cmd);
3388
3389unlock:
3390 hci_dev_unlock(hdev);
3391}
3392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003393static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003394 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003395{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003396 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003397 struct pending_cmd *cmd;
3398 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003399 int err;
3400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003401 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003402
Johan Hedberg56f87902013-10-02 13:43:13 +03003403 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3404 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003405 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3406 MGMT_STATUS_NOT_SUPPORTED);
3407
Johan Hedberga7e80f22013-01-09 16:05:19 +02003408 if (cp->val != 0x00 && cp->val != 0x01)
3409 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3410 MGMT_STATUS_INVALID_PARAMS);
3411
Johan Hedberg5400c042012-02-21 16:40:33 +02003412 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003413 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003414 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003415
3416 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003417 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003418 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003419
3420 hci_dev_lock(hdev);
3421
Johan Hedberg05cbf292013-03-15 17:07:07 -05003422 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3423 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3424 MGMT_STATUS_BUSY);
3425 goto unlock;
3426 }
3427
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003428 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3429 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3430 hdev);
3431 goto unlock;
3432 }
3433
Johan Hedberg33e38b32013-03-15 17:07:05 -05003434 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3435 data, len);
3436 if (!cmd) {
3437 err = -ENOMEM;
3438 goto unlock;
3439 }
3440
3441 hci_req_init(&req, hdev);
3442
Johan Hedberg406d7802013-03-15 17:07:09 -05003443 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003444
3445 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003446 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003447 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003448 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003449 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003450 }
3451
Johan Hedberg33e38b32013-03-15 17:07:05 -05003452unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003453 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003454
Antti Julkuf6422ec2011-06-22 13:11:56 +03003455 return err;
3456}
3457
Johan Hedberg0663ca22013-10-02 13:43:14 +03003458static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3459{
3460 struct pending_cmd *cmd;
3461
3462 BT_DBG("status 0x%02x", status);
3463
3464 hci_dev_lock(hdev);
3465
3466 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3467 if (!cmd)
3468 goto unlock;
3469
3470 if (status) {
3471 u8 mgmt_err = mgmt_status(status);
3472
3473 /* We need to restore the flag if related HCI commands
3474 * failed.
3475 */
3476 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3477
3478 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3479 } else {
3480 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3481 new_settings(hdev, cmd->sk);
3482 }
3483
3484 mgmt_pending_remove(cmd);
3485
3486unlock:
3487 hci_dev_unlock(hdev);
3488}
3489
3490static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3491{
3492 struct mgmt_mode *cp = data;
3493 struct pending_cmd *cmd;
3494 struct hci_request req;
3495 int err;
3496
3497 BT_DBG("request for %s", hdev->name);
3498
3499 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3500 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3501 MGMT_STATUS_NOT_SUPPORTED);
3502
3503 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3504 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3505 MGMT_STATUS_REJECTED);
3506
3507 if (cp->val != 0x00 && cp->val != 0x01)
3508 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3509 MGMT_STATUS_INVALID_PARAMS);
3510
3511 hci_dev_lock(hdev);
3512
3513 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3514 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3515 goto unlock;
3516 }
3517
3518 if (!hdev_is_powered(hdev)) {
3519 if (!cp->val) {
3520 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3521 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3522 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3523 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3524 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3525 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3526 }
3527
3528 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3529
3530 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3531 if (err < 0)
3532 goto unlock;
3533
3534 err = new_settings(hdev, sk);
3535 goto unlock;
3536 }
3537
3538 /* Reject disabling when powered on */
3539 if (!cp->val) {
3540 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3541 MGMT_STATUS_REJECTED);
3542 goto unlock;
3543 }
3544
3545 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3546 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3547 MGMT_STATUS_BUSY);
3548 goto unlock;
3549 }
3550
3551 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3552 if (!cmd) {
3553 err = -ENOMEM;
3554 goto unlock;
3555 }
3556
3557 /* We need to flip the bit already here so that hci_update_ad
3558 * generates the correct flags.
3559 */
3560 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3561
3562 hci_req_init(&req, hdev);
3563 hci_update_ad(&req);
3564 err = hci_req_run(&req, set_bredr_complete);
3565 if (err < 0)
3566 mgmt_pending_remove(cmd);
3567
3568unlock:
3569 hci_dev_unlock(hdev);
3570 return err;
3571}
3572
Johan Hedberg3f706b72013-01-20 14:27:16 +02003573static bool ltk_is_valid(struct mgmt_ltk_info *key)
3574{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003575 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3576 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003577 if (key->master != 0x00 && key->master != 0x01)
3578 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003579 if (!bdaddr_type_is_le(key->addr.type))
3580 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003581 return true;
3582}
3583
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003584static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003585 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003586{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003587 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3588 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003589 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003590
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003591 BT_DBG("request for %s", hdev->name);
3592
3593 if (!lmp_le_capable(hdev))
3594 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3595 MGMT_STATUS_NOT_SUPPORTED);
3596
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003597 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003598
3599 expected_len = sizeof(*cp) + key_count *
3600 sizeof(struct mgmt_ltk_info);
3601 if (expected_len != len) {
3602 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003603 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003604 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003605 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003606 }
3607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003608 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003609
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003610 for (i = 0; i < key_count; i++) {
3611 struct mgmt_ltk_info *key = &cp->keys[i];
3612
Johan Hedberg3f706b72013-01-20 14:27:16 +02003613 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003614 return cmd_status(sk, hdev->id,
3615 MGMT_OP_LOAD_LONG_TERM_KEYS,
3616 MGMT_STATUS_INVALID_PARAMS);
3617 }
3618
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003619 hci_dev_lock(hdev);
3620
3621 hci_smp_ltks_clear(hdev);
3622
3623 for (i = 0; i < key_count; i++) {
3624 struct mgmt_ltk_info *key = &cp->keys[i];
3625 u8 type;
3626
3627 if (key->master)
3628 type = HCI_SMP_LTK;
3629 else
3630 type = HCI_SMP_LTK_SLAVE;
3631
Hemant Gupta4596fde2012-04-16 14:57:40 +05303632 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003633 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003634 type, 0, key->authenticated, key->val,
3635 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003636 }
3637
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003638 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3639 NULL, 0);
3640
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003641 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003642
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003643 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003644}
3645
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003646static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003647 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3648 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003649 bool var_len;
3650 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003651} mgmt_handlers[] = {
3652 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003653 { read_version, false, MGMT_READ_VERSION_SIZE },
3654 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3655 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3656 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3657 { set_powered, false, MGMT_SETTING_SIZE },
3658 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3659 { set_connectable, false, MGMT_SETTING_SIZE },
3660 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3661 { set_pairable, false, MGMT_SETTING_SIZE },
3662 { set_link_security, false, MGMT_SETTING_SIZE },
3663 { set_ssp, false, MGMT_SETTING_SIZE },
3664 { set_hs, false, MGMT_SETTING_SIZE },
3665 { set_le, false, MGMT_SETTING_SIZE },
3666 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3667 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3668 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3669 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3670 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3671 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3672 { disconnect, false, MGMT_DISCONNECT_SIZE },
3673 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3674 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3675 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3676 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3677 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3678 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3679 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3680 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3681 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3682 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3683 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3684 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3685 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3686 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3687 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3688 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3689 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3690 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3691 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003692 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003693 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003694 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003695 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003696};
3697
3698
Johan Hedberg03811012010-12-08 00:21:06 +02003699int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3700{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003701 void *buf;
3702 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003703 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003704 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003705 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003706 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003707 int err;
3708
3709 BT_DBG("got %zu bytes", msglen);
3710
3711 if (msglen < sizeof(*hdr))
3712 return -EINVAL;
3713
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003714 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003715 if (!buf)
3716 return -ENOMEM;
3717
3718 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3719 err = -EFAULT;
3720 goto done;
3721 }
3722
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003723 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003724 opcode = __le16_to_cpu(hdr->opcode);
3725 index = __le16_to_cpu(hdr->index);
3726 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003727
3728 if (len != msglen - sizeof(*hdr)) {
3729 err = -EINVAL;
3730 goto done;
3731 }
3732
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003733 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003734 hdev = hci_dev_get(index);
3735 if (!hdev) {
3736 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003737 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003738 goto done;
3739 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003740
3741 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3742 err = cmd_status(sk, index, opcode,
3743 MGMT_STATUS_INVALID_INDEX);
3744 goto done;
3745 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003746 }
3747
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003748 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003749 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003750 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003751 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003752 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003753 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003754 }
3755
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003756 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003757 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003758 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003759 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003760 goto done;
3761 }
3762
Johan Hedbergbe22b542012-03-01 22:24:41 +02003763 handler = &mgmt_handlers[opcode];
3764
3765 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003766 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003767 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003768 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003769 goto done;
3770 }
3771
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003772 if (hdev)
3773 mgmt_init_hdev(sk, hdev);
3774
3775 cp = buf + sizeof(*hdr);
3776
Johan Hedbergbe22b542012-03-01 22:24:41 +02003777 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003778 if (err < 0)
3779 goto done;
3780
Johan Hedberg03811012010-12-08 00:21:06 +02003781 err = msglen;
3782
3783done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003784 if (hdev)
3785 hci_dev_put(hdev);
3786
Johan Hedberg03811012010-12-08 00:21:06 +02003787 kfree(buf);
3788 return err;
3789}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003790
Johan Hedberg744cf192011-11-08 20:40:14 +02003791int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003792{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003793 if (!mgmt_valid_hdev(hdev))
3794 return -ENOTSUPP;
3795
Johan Hedberg744cf192011-11-08 20:40:14 +02003796 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003797}
3798
Johan Hedberg744cf192011-11-08 20:40:14 +02003799int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003800{
Johan Hedberg5f159032012-03-02 03:13:19 +02003801 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003802
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003803 if (!mgmt_valid_hdev(hdev))
3804 return -ENOTSUPP;
3805
Johan Hedberg744cf192011-11-08 20:40:14 +02003806 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003807
Johan Hedberg744cf192011-11-08 20:40:14 +02003808 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003809}
3810
Johan Hedberg890ea892013-03-15 17:06:52 -05003811static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003812{
Johan Hedberg890ea892013-03-15 17:06:52 -05003813 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003814 u8 scan = 0;
3815
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003816 /* Ensure that fast connectable is disabled. This function will
3817 * not do anything if the page scan parameters are already what
3818 * they should be.
3819 */
3820 write_fast_connectable(req, false);
3821
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003822 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3823 scan |= SCAN_PAGE;
3824 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3825 scan |= SCAN_INQUIRY;
3826
Johan Hedberg890ea892013-03-15 17:06:52 -05003827 if (scan)
3828 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003829}
3830
Johan Hedberg229ab392013-03-15 17:06:53 -05003831static void powered_complete(struct hci_dev *hdev, u8 status)
3832{
3833 struct cmd_lookup match = { NULL, hdev };
3834
3835 BT_DBG("status 0x%02x", status);
3836
3837 hci_dev_lock(hdev);
3838
3839 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3840
3841 new_settings(hdev, match.sk);
3842
3843 hci_dev_unlock(hdev);
3844
3845 if (match.sk)
3846 sock_put(match.sk);
3847}
3848
Johan Hedberg70da6242013-03-15 17:06:51 -05003849static int powered_update_hci(struct hci_dev *hdev)
3850{
Johan Hedberg890ea892013-03-15 17:06:52 -05003851 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003852 u8 link_sec;
3853
Johan Hedberg890ea892013-03-15 17:06:52 -05003854 hci_req_init(&req, hdev);
3855
Johan Hedberg70da6242013-03-15 17:06:51 -05003856 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3857 !lmp_host_ssp_capable(hdev)) {
3858 u8 ssp = 1;
3859
Johan Hedberg890ea892013-03-15 17:06:52 -05003860 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003861 }
3862
Johan Hedbergc73eee92013-04-19 18:35:21 +03003863 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3864 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003865 struct hci_cp_write_le_host_supported cp;
3866
3867 cp.le = 1;
3868 cp.simul = lmp_le_br_capable(hdev);
3869
3870 /* Check first if we already have the right
3871 * host state (host features set)
3872 */
3873 if (cp.le != lmp_host_le_capable(hdev) ||
3874 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003875 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3876 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003877
3878 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3879 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003880 }
3881
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003882 if (lmp_le_capable(hdev)) {
3883 /* Set random address to static address if configured */
3884 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3885 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3886 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003887
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003888 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3889 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003890 }
3891
Johan Hedberg70da6242013-03-15 17:06:51 -05003892 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3893 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003894 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3895 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003896
3897 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003898 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3899 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003900 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003901 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003902 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003903 }
3904
Johan Hedberg229ab392013-03-15 17:06:53 -05003905 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003906}
3907
Johan Hedberg744cf192011-11-08 20:40:14 +02003908int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003909{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003910 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003911 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3912 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003913 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003914
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003915 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3916 return 0;
3917
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003918 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003919 if (powered_update_hci(hdev) == 0)
3920 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003921
Johan Hedberg229ab392013-03-15 17:06:53 -05003922 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3923 &match);
3924 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003925 }
3926
Johan Hedberg229ab392013-03-15 17:06:53 -05003927 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3928 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3929
3930 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3931 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3932 zero_cod, sizeof(zero_cod), NULL);
3933
3934new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003935 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003936
3937 if (match.sk)
3938 sock_put(match.sk);
3939
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003940 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003941}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003942
Johan Hedberg96570ff2013-05-29 09:51:29 +03003943int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3944{
3945 struct pending_cmd *cmd;
3946 u8 status;
3947
3948 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3949 if (!cmd)
3950 return -ENOENT;
3951
3952 if (err == -ERFKILL)
3953 status = MGMT_STATUS_RFKILLED;
3954 else
3955 status = MGMT_STATUS_FAILED;
3956
3957 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3958
3959 mgmt_pending_remove(cmd);
3960
3961 return err;
3962}
3963
Johan Hedberg744cf192011-11-08 20:40:14 +02003964int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003965{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003966 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003967 bool changed = false;
3968 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003969
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003970 if (discoverable) {
3971 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3972 changed = true;
3973 } else {
3974 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3975 changed = true;
3976 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003977
Johan Hedberged9b5f22012-02-21 20:47:06 +02003978 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003979 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003980
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003981 if (changed)
3982 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003983
Johan Hedberg73f22f62010-12-29 16:00:25 +02003984 if (match.sk)
3985 sock_put(match.sk);
3986
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003987 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003988}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003989
Johan Hedberg744cf192011-11-08 20:40:14 +02003990int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003991{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003992 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003993 bool changed = false;
3994 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003995
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003996 if (connectable) {
3997 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3998 changed = true;
3999 } else {
4000 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4001 changed = true;
4002 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004003
Johan Hedberg2b76f452013-03-15 17:07:04 -05004004 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004005
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004006 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004007 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004008
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004009 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004010}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004011
Johan Hedberg744cf192011-11-08 20:40:14 +02004012int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004013{
Johan Hedbergca69b792011-11-11 18:10:00 +02004014 u8 mgmt_err = mgmt_status(status);
4015
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004016 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004017 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004018 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004019
4020 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004021 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004022 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004023
4024 return 0;
4025}
4026
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004027int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4028 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004029{
Johan Hedberg86742e12011-11-07 23:13:38 +02004030 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004031
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004032 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004033
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004034 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004035 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004036 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004037 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004038 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004039 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004040
Johan Hedberg744cf192011-11-08 20:40:14 +02004041 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004042}
Johan Hedbergf7520542011-01-20 12:34:39 +02004043
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004044int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4045{
4046 struct mgmt_ev_new_long_term_key ev;
4047
4048 memset(&ev, 0, sizeof(ev));
4049
4050 ev.store_hint = persistent;
4051 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004052 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004053 ev.key.authenticated = key->authenticated;
4054 ev.key.enc_size = key->enc_size;
4055 ev.key.ediv = key->ediv;
4056
4057 if (key->type == HCI_SMP_LTK)
4058 ev.key.master = 1;
4059
4060 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4061 memcpy(ev.key.val, key->val, sizeof(key->val));
4062
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004063 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4064 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004065}
4066
Johan Hedbergafc747a2012-01-15 18:11:07 +02004067int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004068 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4069 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004070{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004071 char buf[512];
4072 struct mgmt_ev_device_connected *ev = (void *) buf;
4073 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004074
Johan Hedbergb644ba32012-01-17 21:48:47 +02004075 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004076 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004077
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004078 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004079
Johan Hedbergb644ba32012-01-17 21:48:47 +02004080 if (name_len > 0)
4081 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004082 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004083
4084 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004085 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004086 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004087
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004088 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004089
4090 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004091 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004092}
4093
Johan Hedberg8962ee72011-01-20 12:40:27 +02004094static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4095{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004096 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004097 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004098 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004099
Johan Hedberg88c3df12012-02-09 14:27:38 +02004100 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4101 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004102
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004103 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004104 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004105
4106 *sk = cmd->sk;
4107 sock_hold(*sk);
4108
Johan Hedberga664b5b2011-02-19 12:06:02 -03004109 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004110}
4111
Johan Hedberg124f6e32012-02-09 13:50:12 +02004112static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004113{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004114 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004115 struct mgmt_cp_unpair_device *cp = cmd->param;
4116 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004117
4118 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004119 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4120 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004121
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004122 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4123
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004124 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004125
4126 mgmt_pending_remove(cmd);
4127}
4128
Johan Hedbergafc747a2012-01-15 18:11:07 +02004129int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004130 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004131{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004132 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004133 struct sock *sk = NULL;
4134 int err;
4135
Johan Hedberg744cf192011-11-08 20:40:14 +02004136 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004137
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004138 bacpy(&ev.addr.bdaddr, bdaddr);
4139 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4140 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004141
Johan Hedbergafc747a2012-01-15 18:11:07 +02004142 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004143 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004144
4145 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004146 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004147
Johan Hedberg124f6e32012-02-09 13:50:12 +02004148 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004149 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004150
Johan Hedberg8962ee72011-01-20 12:40:27 +02004151 return err;
4152}
4153
Johan Hedberg88c3df12012-02-09 14:27:38 +02004154int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004155 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004156{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004157 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004158 struct pending_cmd *cmd;
4159 int err;
4160
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004161 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4162 hdev);
4163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004164 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004165 if (!cmd)
4166 return -ENOENT;
4167
Johan Hedberg88c3df12012-02-09 14:27:38 +02004168 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004169 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004170
Johan Hedberg88c3df12012-02-09 14:27:38 +02004171 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004172 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004173
Johan Hedberga664b5b2011-02-19 12:06:02 -03004174 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004175
4176 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004177}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004178
Johan Hedberg48264f02011-11-09 13:58:58 +02004179int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004180 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004181{
4182 struct mgmt_ev_connect_failed ev;
4183
Johan Hedberg4c659c32011-11-07 23:13:39 +02004184 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004185 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004186 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004187
Johan Hedberg744cf192011-11-08 20:40:14 +02004188 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004189}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004190
Johan Hedberg744cf192011-11-08 20:40:14 +02004191int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004192{
4193 struct mgmt_ev_pin_code_request ev;
4194
Johan Hedbergd8457692012-02-17 14:24:57 +02004195 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004196 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004197 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004198
Johan Hedberg744cf192011-11-08 20:40:14 +02004199 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004200 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004201}
4202
Johan Hedberg744cf192011-11-08 20:40:14 +02004203int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004204 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004205{
4206 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004207 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004208 int err;
4209
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004210 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004211 if (!cmd)
4212 return -ENOENT;
4213
Johan Hedbergd8457692012-02-17 14:24:57 +02004214 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004215 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004216
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004217 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004218 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004219
Johan Hedberga664b5b2011-02-19 12:06:02 -03004220 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004221
4222 return err;
4223}
4224
Johan Hedberg744cf192011-11-08 20:40:14 +02004225int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004226 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004227{
4228 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004229 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004230 int err;
4231
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004232 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004233 if (!cmd)
4234 return -ENOENT;
4235
Johan Hedbergd8457692012-02-17 14:24:57 +02004236 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004237 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004238
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004239 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004240 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004241
Johan Hedberga664b5b2011-02-19 12:06:02 -03004242 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004243
4244 return err;
4245}
Johan Hedberga5c29682011-02-19 12:05:57 -03004246
Johan Hedberg744cf192011-11-08 20:40:14 +02004247int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004248 u8 link_type, u8 addr_type, __le32 value,
4249 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004250{
4251 struct mgmt_ev_user_confirm_request ev;
4252
Johan Hedberg744cf192011-11-08 20:40:14 +02004253 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004254
Johan Hedberg272d90d2012-02-09 15:26:12 +02004255 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004256 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004257 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004258 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004259
Johan Hedberg744cf192011-11-08 20:40:14 +02004260 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004261 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004262}
4263
Johan Hedberg272d90d2012-02-09 15:26:12 +02004264int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004265 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004266{
4267 struct mgmt_ev_user_passkey_request ev;
4268
4269 BT_DBG("%s", hdev->name);
4270
Johan Hedberg272d90d2012-02-09 15:26:12 +02004271 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004272 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004273
4274 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004275 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004276}
4277
Brian Gix0df4c182011-11-16 13:53:13 -08004278static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004279 u8 link_type, u8 addr_type, u8 status,
4280 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004281{
4282 struct pending_cmd *cmd;
4283 struct mgmt_rp_user_confirm_reply rp;
4284 int err;
4285
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004286 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004287 if (!cmd)
4288 return -ENOENT;
4289
Johan Hedberg272d90d2012-02-09 15:26:12 +02004290 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004291 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004292 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004293 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004294
Johan Hedberga664b5b2011-02-19 12:06:02 -03004295 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004296
4297 return err;
4298}
4299
Johan Hedberg744cf192011-11-08 20:40:14 +02004300int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004301 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004302{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004303 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004304 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004305}
4306
Johan Hedberg272d90d2012-02-09 15:26:12 +02004307int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004308 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004309{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004310 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004311 status,
4312 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004313}
Johan Hedberg2a611692011-02-19 12:06:00 -03004314
Brian Gix604086b2011-11-23 08:28:33 -08004315int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004316 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004317{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004318 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004319 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004320}
4321
Johan Hedberg272d90d2012-02-09 15:26:12 +02004322int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004323 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004324{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004325 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004326 status,
4327 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004328}
4329
Johan Hedberg92a25252012-09-06 18:39:26 +03004330int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4331 u8 link_type, u8 addr_type, u32 passkey,
4332 u8 entered)
4333{
4334 struct mgmt_ev_passkey_notify ev;
4335
4336 BT_DBG("%s", hdev->name);
4337
4338 bacpy(&ev.addr.bdaddr, bdaddr);
4339 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4340 ev.passkey = __cpu_to_le32(passkey);
4341 ev.entered = entered;
4342
4343 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4344}
4345
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004346int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004347 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004348{
4349 struct mgmt_ev_auth_failed ev;
4350
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004351 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004352 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004353 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004354
Johan Hedberg744cf192011-11-08 20:40:14 +02004355 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004356}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004357
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004358int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4359{
4360 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004361 bool changed = false;
4362 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004363
4364 if (status) {
4365 u8 mgmt_err = mgmt_status(status);
4366 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004367 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004368 return 0;
4369 }
4370
Johan Hedberg47990ea2012-02-22 11:58:37 +02004371 if (test_bit(HCI_AUTH, &hdev->flags)) {
4372 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4373 changed = true;
4374 } else {
4375 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4376 changed = true;
4377 }
4378
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004379 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004380 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004381
Johan Hedberg47990ea2012-02-22 11:58:37 +02004382 if (changed)
4383 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004384
4385 if (match.sk)
4386 sock_put(match.sk);
4387
4388 return err;
4389}
4390
Johan Hedberg890ea892013-03-15 17:06:52 -05004391static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004392{
Johan Hedberg890ea892013-03-15 17:06:52 -05004393 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004394 struct hci_cp_write_eir cp;
4395
Johan Hedberg976eb202012-10-24 21:12:01 +03004396 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004397 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004398
Johan Hedbergc80da272012-02-22 15:38:48 +02004399 memset(hdev->eir, 0, sizeof(hdev->eir));
4400
Johan Hedbergcacaf522012-02-21 00:52:42 +02004401 memset(&cp, 0, sizeof(cp));
4402
Johan Hedberg890ea892013-03-15 17:06:52 -05004403 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004404}
4405
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004406int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004407{
4408 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004409 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004410 bool changed = false;
4411 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004412
4413 if (status) {
4414 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004415
4416 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004417 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004418 err = new_settings(hdev, NULL);
4419
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004420 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4421 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004422
4423 return err;
4424 }
4425
4426 if (enable) {
4427 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4428 changed = true;
4429 } else {
4430 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4431 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004432 }
4433
4434 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4435
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004436 if (changed)
4437 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004438
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004439 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004440 sock_put(match.sk);
4441
Johan Hedberg890ea892013-03-15 17:06:52 -05004442 hci_req_init(&req, hdev);
4443
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004444 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004445 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004446 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004447 clear_eir(&req);
4448
4449 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004450
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004451 return err;
4452}
4453
Johan Hedberg92da6092013-03-15 17:06:55 -05004454static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004455{
4456 struct cmd_lookup *match = data;
4457
Johan Hedberg90e70452012-02-23 23:09:40 +02004458 if (match->sk == NULL) {
4459 match->sk = cmd->sk;
4460 sock_hold(match->sk);
4461 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004462}
4463
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004464int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004465 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004466{
Johan Hedberg90e70452012-02-23 23:09:40 +02004467 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4468 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004469
Johan Hedberg92da6092013-03-15 17:06:55 -05004470 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4471 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4472 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004473
4474 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004475 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4476 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004477
4478 if (match.sk)
4479 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004480
4481 return err;
4482}
4483
Johan Hedberg744cf192011-11-08 20:40:14 +02004484int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004485{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004486 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004487 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004488
Johan Hedberg13928972013-03-15 17:07:00 -05004489 if (status)
4490 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004491
4492 memset(&ev, 0, sizeof(ev));
4493 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004494 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004495
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004496 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004497 if (!cmd) {
4498 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004499
Johan Hedberg13928972013-03-15 17:07:00 -05004500 /* If this is a HCI command related to powering on the
4501 * HCI dev don't send any mgmt signals.
4502 */
4503 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4504 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004505 }
4506
Johan Hedberg13928972013-03-15 17:07:00 -05004507 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4508 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004509}
Szymon Jancc35938b2011-03-22 13:12:21 +01004510
Johan Hedberg744cf192011-11-08 20:40:14 +02004511int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004512 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004513{
4514 struct pending_cmd *cmd;
4515 int err;
4516
Johan Hedberg744cf192011-11-08 20:40:14 +02004517 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004518
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004519 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004520 if (!cmd)
4521 return -ENOENT;
4522
4523 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004524 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4525 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004526 } else {
4527 struct mgmt_rp_read_local_oob_data rp;
4528
4529 memcpy(rp.hash, hash, sizeof(rp.hash));
4530 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4531
Johan Hedberg744cf192011-11-08 20:40:14 +02004532 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004533 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4534 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004535 }
4536
4537 mgmt_pending_remove(cmd);
4538
4539 return err;
4540}
Johan Hedberge17acd42011-03-30 23:57:16 +03004541
Johan Hedberg48264f02011-11-09 13:58:58 +02004542int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004543 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4544 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004545{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004546 char buf[512];
4547 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004548 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004549
Andre Guedes12602d02013-04-30 15:29:40 -03004550 if (!hci_discovery_active(hdev))
4551 return -EPERM;
4552
Johan Hedberg1dc06092012-01-15 21:01:23 +02004553 /* Leave 5 bytes for a potential CoD field */
4554 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004555 return -EINVAL;
4556
Johan Hedberg1dc06092012-01-15 21:01:23 +02004557 memset(buf, 0, sizeof(buf));
4558
Johan Hedberge319d2e2012-01-15 19:51:59 +02004559 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004560 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004561 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004562 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304563 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004564 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304565 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004566
Johan Hedberg1dc06092012-01-15 21:01:23 +02004567 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004568 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004569
Johan Hedberg1dc06092012-01-15 21:01:23 +02004570 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4571 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004572 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004573
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004574 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004575 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004576
Johan Hedberge319d2e2012-01-15 19:51:59 +02004577 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004578}
Johan Hedberga88a9652011-03-30 13:18:12 +03004579
Johan Hedbergb644ba32012-01-17 21:48:47 +02004580int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004581 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004582{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004583 struct mgmt_ev_device_found *ev;
4584 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4585 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004586
Johan Hedbergb644ba32012-01-17 21:48:47 +02004587 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004588
Johan Hedbergb644ba32012-01-17 21:48:47 +02004589 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004590
Johan Hedbergb644ba32012-01-17 21:48:47 +02004591 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004592 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004593 ev->rssi = rssi;
4594
4595 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004596 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004597
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004598 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004599
Johan Hedberg053c7e02012-02-04 00:06:00 +02004600 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004601 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004602}
Johan Hedberg314b2382011-04-27 10:29:57 -04004603
Johan Hedberg744cf192011-11-08 20:40:14 +02004604int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004605{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004606 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004607 struct pending_cmd *cmd;
4608
Andre Guedes343fb142011-11-22 17:14:19 -03004609 BT_DBG("%s discovering %u", hdev->name, discovering);
4610
Johan Hedberg164a6e72011-11-01 17:06:44 +02004611 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004612 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004613 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004614 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004615
4616 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004617 u8 type = hdev->discovery.type;
4618
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004619 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4620 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004621 mgmt_pending_remove(cmd);
4622 }
4623
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004624 memset(&ev, 0, sizeof(ev));
4625 ev.type = hdev->discovery.type;
4626 ev.discovering = discovering;
4627
4628 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004629}
Antti Julku5e762442011-08-25 16:48:02 +03004630
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004631int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004632{
4633 struct pending_cmd *cmd;
4634 struct mgmt_ev_device_blocked ev;
4635
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004636 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004637
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004638 bacpy(&ev.addr.bdaddr, bdaddr);
4639 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004640
Johan Hedberg744cf192011-11-08 20:40:14 +02004641 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004642 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004643}
4644
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004645int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004646{
4647 struct pending_cmd *cmd;
4648 struct mgmt_ev_device_unblocked ev;
4649
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004650 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004651
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004652 bacpy(&ev.addr.bdaddr, bdaddr);
4653 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004654
Johan Hedberg744cf192011-11-08 20:40:14 +02004655 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004656 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004657}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004658
4659static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4660{
4661 BT_DBG("%s status %u", hdev->name, status);
4662
4663 /* Clear the advertising mgmt setting if we failed to re-enable it */
4664 if (status) {
4665 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004666 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004667 }
4668}
4669
4670void mgmt_reenable_advertising(struct hci_dev *hdev)
4671{
4672 struct hci_request req;
4673
4674 if (hdev->conn_hash.le_num)
4675 return;
4676
4677 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4678 return;
4679
4680 hci_req_init(&req, hdev);
4681 enable_advertising(&req);
4682
4683 /* If this fails we have no option but to let user space know
4684 * that we've disabled advertising.
4685 */
4686 if (hci_req_run(&req, adv_enable_complete) < 0) {
4687 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004688 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004689 }
4690}