blob: 1b5b10fab54552d54d98df7ddb76fe5a9240422e [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060038#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030079 MGMT_OP_SET_ADVERTISING,
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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200206
Andre Guedes790eff42012-06-07 19:05:46 -0300207 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200223 kfree_skb(skb);
224
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300225 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200226}
227
Johan Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-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;
383 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200384
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100385 if (enable_hs)
386 settings |= MGMT_SETTING_HS;
387
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300388 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200389 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300390 settings |= MGMT_SETTING_ADVERTISING;
391 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200392
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200393 return settings;
394}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200395
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396static u32 get_current_settings(struct hci_dev *hdev)
397{
398 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200399
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200400 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100401 settings |= MGMT_SETTING_POWERED;
402
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200403 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200404 settings |= MGMT_SETTING_CONNECTABLE;
405
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500406 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
407 settings |= MGMT_SETTING_FAST_CONNECTABLE;
408
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200409 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_DISCOVERABLE;
411
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200412 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_PAIRABLE;
414
Andre Guedesed3fa312012-07-24 15:03:46 -0300415 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_BREDR;
417
Johan Hedberg06199cf2012-02-22 16:37:11 +0200418 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200420
Johan Hedberg47990ea2012-02-22 11:58:37 +0200421 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200424 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200426
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200427 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
428 settings |= MGMT_SETTING_HS;
429
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300430 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
431 settings |= MGMT_SETTING_ADVERTISING;
432
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200433 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200434}
435
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300436#define PNP_INFO_SVCLASS_ID 0x1200
437
Johan Hedberg213202e2013-01-27 00:31:33 +0200438static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
439{
440 u8 *ptr = data, *uuids_start = NULL;
441 struct bt_uuid *uuid;
442
443 if (len < 4)
444 return ptr;
445
446 list_for_each_entry(uuid, &hdev->uuids, list) {
447 u16 uuid16;
448
449 if (uuid->size != 16)
450 continue;
451
452 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
453 if (uuid16 < 0x1100)
454 continue;
455
456 if (uuid16 == PNP_INFO_SVCLASS_ID)
457 continue;
458
459 if (!uuids_start) {
460 uuids_start = ptr;
461 uuids_start[0] = 1;
462 uuids_start[1] = EIR_UUID16_ALL;
463 ptr += 2;
464 }
465
466 /* Stop if not enough space to put next UUID */
467 if ((ptr - data) + sizeof(u16) > len) {
468 uuids_start[1] = EIR_UUID16_SOME;
469 break;
470 }
471
472 *ptr++ = (uuid16 & 0x00ff);
473 *ptr++ = (uuid16 & 0xff00) >> 8;
474 uuids_start[0] += sizeof(uuid16);
475 }
476
477 return ptr;
478}
479
Johan Hedbergcdf19632013-01-27 00:31:34 +0200480static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
481{
482 u8 *ptr = data, *uuids_start = NULL;
483 struct bt_uuid *uuid;
484
485 if (len < 6)
486 return ptr;
487
488 list_for_each_entry(uuid, &hdev->uuids, list) {
489 if (uuid->size != 32)
490 continue;
491
492 if (!uuids_start) {
493 uuids_start = ptr;
494 uuids_start[0] = 1;
495 uuids_start[1] = EIR_UUID32_ALL;
496 ptr += 2;
497 }
498
499 /* Stop if not enough space to put next UUID */
500 if ((ptr - data) + sizeof(u32) > len) {
501 uuids_start[1] = EIR_UUID32_SOME;
502 break;
503 }
504
505 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
506 ptr += sizeof(u32);
507 uuids_start[0] += sizeof(u32);
508 }
509
510 return ptr;
511}
512
Johan Hedbergc00d5752013-01-27 00:31:35 +0200513static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
514{
515 u8 *ptr = data, *uuids_start = NULL;
516 struct bt_uuid *uuid;
517
518 if (len < 18)
519 return ptr;
520
521 list_for_each_entry(uuid, &hdev->uuids, list) {
522 if (uuid->size != 128)
523 continue;
524
525 if (!uuids_start) {
526 uuids_start = ptr;
527 uuids_start[0] = 1;
528 uuids_start[1] = EIR_UUID128_ALL;
529 ptr += 2;
530 }
531
532 /* Stop if not enough space to put next UUID */
533 if ((ptr - data) + 16 > len) {
534 uuids_start[1] = EIR_UUID128_SOME;
535 break;
536 }
537
538 memcpy(ptr, uuid->uuid, 16);
539 ptr += 16;
540 uuids_start[0] += 16;
541 }
542
543 return ptr;
544}
545
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300546static void create_eir(struct hci_dev *hdev, u8 *data)
547{
548 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300549 size_t name_len;
550
551 name_len = strlen(hdev->dev_name);
552
553 if (name_len > 0) {
554 /* EIR Data type */
555 if (name_len > 48) {
556 name_len = 48;
557 ptr[1] = EIR_NAME_SHORT;
558 } else
559 ptr[1] = EIR_NAME_COMPLETE;
560
561 /* EIR Data length */
562 ptr[0] = name_len + 1;
563
564 memcpy(ptr + 2, hdev->dev_name, name_len);
565
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300566 ptr += (name_len + 2);
567 }
568
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100569 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700570 ptr[0] = 2;
571 ptr[1] = EIR_TX_POWER;
572 ptr[2] = (u8) hdev->inq_tx_power;
573
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700574 ptr += 3;
575 }
576
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700577 if (hdev->devid_source > 0) {
578 ptr[0] = 9;
579 ptr[1] = EIR_DEVICE_ID;
580
581 put_unaligned_le16(hdev->devid_source, ptr + 2);
582 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
583 put_unaligned_le16(hdev->devid_product, ptr + 6);
584 put_unaligned_le16(hdev->devid_version, ptr + 8);
585
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700586 ptr += 10;
587 }
588
Johan Hedberg213202e2013-01-27 00:31:33 +0200589 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200590 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200591 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300592}
593
Johan Hedberg890ea892013-03-15 17:06:52 -0500594static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595{
Johan Hedberg890ea892013-03-15 17:06:52 -0500596 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300597 struct hci_cp_write_eir cp;
598
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200599 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200601
Johan Hedberg976eb202012-10-24 21:12:01 +0300602 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500603 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300604
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200605 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500606 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300607
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200608 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500609 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300610
611 memset(&cp, 0, sizeof(cp));
612
613 create_eir(hdev, cp.data);
614
615 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500616 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300617
618 memcpy(hdev->eir, cp.data, sizeof(cp.data));
619
Johan Hedberg890ea892013-03-15 17:06:52 -0500620 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300621}
622
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200623static u8 get_service_classes(struct hci_dev *hdev)
624{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300625 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200626 u8 val = 0;
627
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300628 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200629 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200630
631 return val;
632}
633
Johan Hedberg890ea892013-03-15 17:06:52 -0500634static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200635{
Johan Hedberg890ea892013-03-15 17:06:52 -0500636 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200637 u8 cod[3];
638
639 BT_DBG("%s", hdev->name);
640
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200641 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500642 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200643
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200644 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500645 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200646
647 cod[0] = hdev->minor_class;
648 cod[1] = hdev->major_class;
649 cod[2] = get_service_classes(hdev);
650
651 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500652 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200653
Johan Hedberg890ea892013-03-15 17:06:52 -0500654 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200655}
656
Johan Hedberg7d785252011-12-15 00:47:39 +0200657static void service_cache_off(struct work_struct *work)
658{
659 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300660 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500661 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200662
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200663 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200664 return;
665
Johan Hedberg890ea892013-03-15 17:06:52 -0500666 hci_req_init(&req, hdev);
667
Johan Hedberg7d785252011-12-15 00:47:39 +0200668 hci_dev_lock(hdev);
669
Johan Hedberg890ea892013-03-15 17:06:52 -0500670 update_eir(&req);
671 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200672
673 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500674
675 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200676}
677
Johan Hedberg6a919082012-02-28 06:17:26 +0200678static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200679{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200680 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200681 return;
682
Johan Hedberg4f87da82012-03-02 19:55:56 +0200683 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200684
Johan Hedberg4f87da82012-03-02 19:55:56 +0200685 /* Non-mgmt controlled devices get this bit set
686 * implicitly so that pairing works for them, however
687 * for mgmt we require user-space to explicitly enable
688 * it
689 */
690 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200691}
692
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200693static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300694 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200695{
696 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200697
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200698 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200699
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300700 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200701
Johan Hedberg03811012010-12-08 00:21:06 +0200702 memset(&rp, 0, sizeof(rp));
703
Johan Hedberg03811012010-12-08 00:21:06 +0200704 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200705
706 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200707 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200708
709 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
710 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
711
712 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200713
714 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200715 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200716
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300717 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200718
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200719 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300720 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200721}
722
723static void mgmt_pending_free(struct pending_cmd *cmd)
724{
725 sock_put(cmd->sk);
726 kfree(cmd->param);
727 kfree(cmd);
728}
729
730static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300731 struct hci_dev *hdev, void *data,
732 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200733{
734 struct pending_cmd *cmd;
735
Andre Guedes12b94562012-06-07 19:05:45 -0300736 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200737 if (!cmd)
738 return NULL;
739
740 cmd->opcode = opcode;
741 cmd->index = hdev->id;
742
Andre Guedes12b94562012-06-07 19:05:45 -0300743 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200744 if (!cmd->param) {
745 kfree(cmd);
746 return NULL;
747 }
748
749 if (data)
750 memcpy(cmd->param, data, len);
751
752 cmd->sk = sk;
753 sock_hold(sk);
754
755 list_add(&cmd->list, &hdev->mgmt_pending);
756
757 return cmd;
758}
759
760static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300761 void (*cb)(struct pending_cmd *cmd,
762 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300763 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200764{
Andre Guedesa3d09352013-02-01 11:21:30 -0300765 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200766
Andre Guedesa3d09352013-02-01 11:21:30 -0300767 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200768 if (opcode > 0 && cmd->opcode != opcode)
769 continue;
770
771 cb(cmd, data);
772 }
773}
774
775static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
776{
777 struct pending_cmd *cmd;
778
779 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
780 if (cmd->opcode == opcode)
781 return cmd;
782 }
783
784 return NULL;
785}
786
787static void mgmt_pending_remove(struct pending_cmd *cmd)
788{
789 list_del(&cmd->list);
790 mgmt_pending_free(cmd);
791}
792
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200793static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200794{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200795 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200796
Johan Hedbergaee9b212012-02-18 15:07:59 +0200797 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300798 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200799}
800
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200801static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300802 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200803{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300804 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200805 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200806 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200808 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200809
Johan Hedberga7e80f22013-01-09 16:05:19 +0200810 if (cp->val != 0x00 && cp->val != 0x01)
811 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
812 MGMT_STATUS_INVALID_PARAMS);
813
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300814 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200815
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300816 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
817 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
818 MGMT_STATUS_BUSY);
819 goto failed;
820 }
821
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100822 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
823 cancel_delayed_work(&hdev->power_off);
824
825 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200826 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
827 data, len);
828 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100829 goto failed;
830 }
831 }
832
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200833 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200834 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200835 goto failed;
836 }
837
Johan Hedberg03811012010-12-08 00:21:06 +0200838 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
839 if (!cmd) {
840 err = -ENOMEM;
841 goto failed;
842 }
843
844 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200845 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200846 else
Johan Hedberg19202572013-01-14 22:33:51 +0200847 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200848
849 err = 0;
850
851failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300852 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200853 return err;
854}
855
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300856static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
857 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200858{
859 struct sk_buff *skb;
860 struct mgmt_hdr *hdr;
861
Andre Guedes790eff42012-06-07 19:05:46 -0300862 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200863 if (!skb)
864 return -ENOMEM;
865
866 hdr = (void *) skb_put(skb, sizeof(*hdr));
867 hdr->opcode = cpu_to_le16(event);
868 if (hdev)
869 hdr->index = cpu_to_le16(hdev->id);
870 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530871 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200872 hdr->len = cpu_to_le16(data_len);
873
874 if (data)
875 memcpy(skb_put(skb, data_len), data, data_len);
876
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100877 /* Time stamp */
878 __net_timestamp(skb);
879
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200880 hci_send_to_control(skb, skip_sk);
881 kfree_skb(skb);
882
883 return 0;
884}
885
886static int new_settings(struct hci_dev *hdev, struct sock *skip)
887{
888 __le32 ev;
889
890 ev = cpu_to_le32(get_current_settings(hdev));
891
892 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
893}
894
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300895struct cmd_lookup {
896 struct sock *sk;
897 struct hci_dev *hdev;
898 u8 mgmt_status;
899};
900
901static void settings_rsp(struct pending_cmd *cmd, void *data)
902{
903 struct cmd_lookup *match = data;
904
905 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
906
907 list_del(&cmd->list);
908
909 if (match->sk == NULL) {
910 match->sk = cmd->sk;
911 sock_hold(match->sk);
912 }
913
914 mgmt_pending_free(cmd);
915}
916
917static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
918{
919 u8 *status = data;
920
921 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
922 mgmt_pending_remove(cmd);
923}
924
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200925static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300926 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200927{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300928 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200929 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200930 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200931 u8 scan;
932 int err;
933
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200934 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200935
Johan Hedberg33c525c2012-10-24 21:11:58 +0300936 if (!lmp_bredr_capable(hdev))
937 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
938 MGMT_STATUS_NOT_SUPPORTED);
939
Johan Hedberga7e80f22013-01-09 16:05:19 +0200940 if (cp->val != 0x00 && cp->val != 0x01)
941 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
942 MGMT_STATUS_INVALID_PARAMS);
943
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700944 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100945 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200946 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300947 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200948
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300949 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200950
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200951 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200952 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300953 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200954 goto failed;
955 }
956
957 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300958 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200959 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300960 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200961 goto failed;
962 }
963
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200964 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200965 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300966 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200967 goto failed;
968 }
969
970 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200971 bool changed = false;
972
973 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
974 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
975 changed = true;
976 }
977
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200978 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200979 if (err < 0)
980 goto failed;
981
982 if (changed)
983 err = new_settings(hdev, sk);
984
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200985 goto failed;
986 }
987
988 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100989 if (hdev->discov_timeout > 0) {
990 cancel_delayed_work(&hdev->discov_off);
991 hdev->discov_timeout = 0;
992 }
993
994 if (cp->val && timeout > 0) {
995 hdev->discov_timeout = timeout;
996 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
997 msecs_to_jiffies(hdev->discov_timeout * 1000));
998 }
999
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001000 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001001 goto failed;
1002 }
1003
1004 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1005 if (!cmd) {
1006 err = -ENOMEM;
1007 goto failed;
1008 }
1009
1010 scan = SCAN_PAGE;
1011
1012 if (cp->val)
1013 scan |= SCAN_INQUIRY;
1014 else
1015 cancel_delayed_work(&hdev->discov_off);
1016
1017 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1018 if (err < 0)
1019 mgmt_pending_remove(cmd);
1020
Johan Hedberg03811012010-12-08 00:21:06 +02001021 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001022 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001023
1024failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001025 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001026 return err;
1027}
1028
Johan Hedberg406d7802013-03-15 17:07:09 -05001029static void write_fast_connectable(struct hci_request *req, bool enable)
1030{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001031 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001032 struct hci_cp_write_page_scan_activity acp;
1033 u8 type;
1034
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001035 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1036 return;
1037
Johan Hedberg406d7802013-03-15 17:07:09 -05001038 if (enable) {
1039 type = PAGE_SCAN_TYPE_INTERLACED;
1040
1041 /* 160 msec page scan interval */
1042 acp.interval = __constant_cpu_to_le16(0x0100);
1043 } else {
1044 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1045
1046 /* default 1.28 sec page scan */
1047 acp.interval = __constant_cpu_to_le16(0x0800);
1048 }
1049
1050 acp.window = __constant_cpu_to_le16(0x0012);
1051
Johan Hedbergbd98b992013-03-15 17:07:13 -05001052 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1053 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1054 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1055 sizeof(acp), &acp);
1056
1057 if (hdev->page_scan_type != type)
1058 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001059}
1060
Johan Hedberg2b76f452013-03-15 17:07:04 -05001061static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1062{
1063 struct pending_cmd *cmd;
1064
1065 BT_DBG("status 0x%02x", status);
1066
1067 hci_dev_lock(hdev);
1068
1069 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1070 if (!cmd)
1071 goto unlock;
1072
1073 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1074
1075 mgmt_pending_remove(cmd);
1076
1077unlock:
1078 hci_dev_unlock(hdev);
1079}
1080
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001081static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001082 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001083{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001084 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001085 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001086 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001087 u8 scan;
1088 int err;
1089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001090 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001091
Johan Hedberg33c525c2012-10-24 21:11:58 +03001092 if (!lmp_bredr_capable(hdev))
1093 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1094 MGMT_STATUS_NOT_SUPPORTED);
1095
Johan Hedberga7e80f22013-01-09 16:05:19 +02001096 if (cp->val != 0x00 && cp->val != 0x01)
1097 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1098 MGMT_STATUS_INVALID_PARAMS);
1099
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001100 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001101
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001102 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001103 bool changed = false;
1104
1105 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1106 changed = true;
1107
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001108 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001109 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001110 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001111 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1112 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1113 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001114
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001115 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001116 if (err < 0)
1117 goto failed;
1118
1119 if (changed)
1120 err = new_settings(hdev, sk);
1121
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001122 goto failed;
1123 }
1124
1125 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001126 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001127 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001128 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001129 goto failed;
1130 }
1131
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001132 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001133 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001134 goto failed;
1135 }
1136
1137 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1138 if (!cmd) {
1139 err = -ENOMEM;
1140 goto failed;
1141 }
1142
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001143 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001144 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001145 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001146 scan = 0;
1147
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001148 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001149 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001150 cancel_delayed_work(&hdev->discov_off);
1151 }
1152
Johan Hedberg2b76f452013-03-15 17:07:04 -05001153 hci_req_init(&req, hdev);
1154
1155 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1156
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001157 /* If we're going from non-connectable to connectable or
1158 * vice-versa when fast connectable is enabled ensure that fast
1159 * connectable gets disabled. write_fast_connectable won't do
1160 * anything if the page scan parameters are already what they
1161 * should be.
1162 */
1163 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001164 write_fast_connectable(&req, false);
1165
Johan Hedberg2b76f452013-03-15 17:07:04 -05001166 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001167 if (err < 0)
1168 mgmt_pending_remove(cmd);
1169
1170failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001171 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001172 return err;
1173}
1174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001175static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001176 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001177{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001178 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001179 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001181 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001182
Johan Hedberga7e80f22013-01-09 16:05:19 +02001183 if (cp->val != 0x00 && cp->val != 0x01)
1184 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1185 MGMT_STATUS_INVALID_PARAMS);
1186
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001187 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001188
1189 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001190 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001191 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001192 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001194 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001195 if (err < 0)
1196 goto failed;
1197
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001198 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001199
1200failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001201 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202 return err;
1203}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001204
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001205static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1206 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001207{
1208 struct mgmt_mode *cp = data;
1209 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001210 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001211 int err;
1212
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001213 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001214
Johan Hedberg33c525c2012-10-24 21:11:58 +03001215 if (!lmp_bredr_capable(hdev))
1216 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1217 MGMT_STATUS_NOT_SUPPORTED);
1218
Johan Hedberga7e80f22013-01-09 16:05:19 +02001219 if (cp->val != 0x00 && cp->val != 0x01)
1220 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1221 MGMT_STATUS_INVALID_PARAMS);
1222
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001223 hci_dev_lock(hdev);
1224
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001225 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001226 bool changed = false;
1227
1228 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001229 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001230 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1231 changed = true;
1232 }
1233
1234 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1235 if (err < 0)
1236 goto failed;
1237
1238 if (changed)
1239 err = new_settings(hdev, sk);
1240
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001241 goto failed;
1242 }
1243
1244 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001245 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001246 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001247 goto failed;
1248 }
1249
1250 val = !!cp->val;
1251
1252 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1253 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1254 goto failed;
1255 }
1256
1257 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1258 if (!cmd) {
1259 err = -ENOMEM;
1260 goto failed;
1261 }
1262
1263 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1264 if (err < 0) {
1265 mgmt_pending_remove(cmd);
1266 goto failed;
1267 }
1268
1269failed:
1270 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001271 return err;
1272}
1273
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001274static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001275{
1276 struct mgmt_mode *cp = data;
1277 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001278 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001279 int err;
1280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001281 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001282
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001283 if (!lmp_ssp_capable(hdev))
1284 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1285 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001286
Johan Hedberga7e80f22013-01-09 16:05:19 +02001287 if (cp->val != 0x00 && cp->val != 0x01)
1288 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1289 MGMT_STATUS_INVALID_PARAMS);
1290
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001291 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001292
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001293 val = !!cp->val;
1294
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001295 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001296 bool changed = false;
1297
1298 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1299 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1300 changed = true;
1301 }
1302
1303 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1304 if (err < 0)
1305 goto failed;
1306
1307 if (changed)
1308 err = new_settings(hdev, sk);
1309
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001310 goto failed;
1311 }
1312
1313 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001314 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1315 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001316 goto failed;
1317 }
1318
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001319 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1320 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1321 goto failed;
1322 }
1323
1324 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1325 if (!cmd) {
1326 err = -ENOMEM;
1327 goto failed;
1328 }
1329
1330 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1331 if (err < 0) {
1332 mgmt_pending_remove(cmd);
1333 goto failed;
1334 }
1335
1336failed:
1337 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001338 return err;
1339}
1340
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001341static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001342{
1343 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001344
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001345 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001346
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001347 if (!enable_hs)
1348 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001349 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001350
Johan Hedberga7e80f22013-01-09 16:05:19 +02001351 if (cp->val != 0x00 && cp->val != 0x01)
1352 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1353 MGMT_STATUS_INVALID_PARAMS);
1354
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001355 if (cp->val)
1356 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1357 else
1358 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001360 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001361}
1362
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001363static void le_enable_complete(struct hci_dev *hdev, u8 status)
1364{
1365 struct cmd_lookup match = { NULL, hdev };
1366
1367 if (status) {
1368 u8 mgmt_err = mgmt_status(status);
1369
1370 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1371 &mgmt_err);
1372 return;
1373 }
1374
1375 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1376
1377 new_settings(hdev, match.sk);
1378
1379 if (match.sk)
1380 sock_put(match.sk);
1381}
1382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001383static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001384{
1385 struct mgmt_mode *cp = data;
1386 struct hci_cp_write_le_host_supported hci_cp;
1387 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001388 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001389 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001390 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001393
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001394 if (!lmp_le_capable(hdev))
1395 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1396 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001397
Johan Hedberga7e80f22013-01-09 16:05:19 +02001398 if (cp->val != 0x00 && cp->val != 0x01)
1399 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1400 MGMT_STATUS_INVALID_PARAMS);
1401
Johan Hedbergc73eee92013-04-19 18:35:21 +03001402 /* LE-only devices do not allow toggling LE on/off */
1403 if (!lmp_bredr_capable(hdev))
1404 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1405 MGMT_STATUS_REJECTED);
1406
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001407 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001408
1409 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001410 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001411
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001412 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001413 bool changed = false;
1414
1415 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1416 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1417 changed = true;
1418 }
1419
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001420 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1421 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1422 changed = true;
1423 }
1424
Johan Hedberg06199cf2012-02-22 16:37:11 +02001425 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1426 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001427 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001428
1429 if (changed)
1430 err = new_settings(hdev, sk);
1431
Johan Hedberg1de028c2012-02-29 19:55:35 -08001432 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001433 }
1434
Johan Hedberg4375f102013-09-25 13:26:10 +03001435 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1436 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001437 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001438 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001439 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001440 }
1441
1442 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1443 if (!cmd) {
1444 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001445 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001446 }
1447
1448 memset(&hci_cp, 0, sizeof(hci_cp));
1449
1450 if (val) {
1451 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001452 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001453 }
1454
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001455 hci_req_init(&req, hdev);
1456
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001457 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1458 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1459
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001460 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1461 &hci_cp);
1462
1463 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301464 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001465 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001466
Johan Hedberg1de028c2012-02-29 19:55:35 -08001467unlock:
1468 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001469 return err;
1470}
1471
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001472/* This is a helper function to test for pending mgmt commands that can
1473 * cause CoD or EIR HCI commands. We can only allow one such pending
1474 * mgmt command at a time since otherwise we cannot easily track what
1475 * the current values are, will be, and based on that calculate if a new
1476 * HCI command needs to be sent and if yes with what value.
1477 */
1478static bool pending_eir_or_class(struct hci_dev *hdev)
1479{
1480 struct pending_cmd *cmd;
1481
1482 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1483 switch (cmd->opcode) {
1484 case MGMT_OP_ADD_UUID:
1485 case MGMT_OP_REMOVE_UUID:
1486 case MGMT_OP_SET_DEV_CLASS:
1487 case MGMT_OP_SET_POWERED:
1488 return true;
1489 }
1490 }
1491
1492 return false;
1493}
1494
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001495static const u8 bluetooth_base_uuid[] = {
1496 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1497 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1498};
1499
1500static u8 get_uuid_size(const u8 *uuid)
1501{
1502 u32 val;
1503
1504 if (memcmp(uuid, bluetooth_base_uuid, 12))
1505 return 128;
1506
1507 val = get_unaligned_le32(&uuid[12]);
1508 if (val > 0xffff)
1509 return 32;
1510
1511 return 16;
1512}
1513
Johan Hedberg92da6092013-03-15 17:06:55 -05001514static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1515{
1516 struct pending_cmd *cmd;
1517
1518 hci_dev_lock(hdev);
1519
1520 cmd = mgmt_pending_find(mgmt_op, hdev);
1521 if (!cmd)
1522 goto unlock;
1523
1524 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1525 hdev->dev_class, 3);
1526
1527 mgmt_pending_remove(cmd);
1528
1529unlock:
1530 hci_dev_unlock(hdev);
1531}
1532
1533static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1534{
1535 BT_DBG("status 0x%02x", status);
1536
1537 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1538}
1539
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001540static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001541{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001542 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001543 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001544 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001545 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001546 int err;
1547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001548 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001549
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001550 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001551
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001552 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001553 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001554 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001555 goto failed;
1556 }
1557
Andre Guedes92c4c202012-06-07 19:05:44 -03001558 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001559 if (!uuid) {
1560 err = -ENOMEM;
1561 goto failed;
1562 }
1563
1564 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001565 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001566 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001567
Johan Hedbergde66aa62013-01-27 00:31:27 +02001568 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001569
Johan Hedberg890ea892013-03-15 17:06:52 -05001570 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001571
Johan Hedberg890ea892013-03-15 17:06:52 -05001572 update_class(&req);
1573 update_eir(&req);
1574
Johan Hedberg92da6092013-03-15 17:06:55 -05001575 err = hci_req_run(&req, add_uuid_complete);
1576 if (err < 0) {
1577 if (err != -ENODATA)
1578 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001579
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001580 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001581 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001582 goto failed;
1583 }
1584
1585 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001586 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001587 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001588 goto failed;
1589 }
1590
1591 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001592
1593failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001594 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001595 return err;
1596}
1597
Johan Hedberg24b78d02012-02-23 23:24:30 +02001598static bool enable_service_cache(struct hci_dev *hdev)
1599{
1600 if (!hdev_is_powered(hdev))
1601 return false;
1602
1603 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001604 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1605 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001606 return true;
1607 }
1608
1609 return false;
1610}
1611
Johan Hedberg92da6092013-03-15 17:06:55 -05001612static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1613{
1614 BT_DBG("status 0x%02x", status);
1615
1616 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1617}
1618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001619static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001620 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001621{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001622 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001623 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001624 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625 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 -05001626 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001627 int err, found;
1628
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001629 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001631 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001632
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001633 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001634 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001635 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001636 goto unlock;
1637 }
1638
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001639 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1640 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001641
Johan Hedberg24b78d02012-02-23 23:24:30 +02001642 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001644 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001645 goto unlock;
1646 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001647
Johan Hedberg9246a862012-02-23 21:33:16 +02001648 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001649 }
1650
1651 found = 0;
1652
Johan Hedberg056341c2013-01-27 00:31:30 +02001653 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001654 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1655 continue;
1656
1657 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001658 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001659 found++;
1660 }
1661
1662 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001663 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001664 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001665 goto unlock;
1666 }
1667
Johan Hedberg9246a862012-02-23 21:33:16 +02001668update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001669 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001670
Johan Hedberg890ea892013-03-15 17:06:52 -05001671 update_class(&req);
1672 update_eir(&req);
1673
Johan Hedberg92da6092013-03-15 17:06:55 -05001674 err = hci_req_run(&req, remove_uuid_complete);
1675 if (err < 0) {
1676 if (err != -ENODATA)
1677 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001678
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001679 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001680 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001681 goto unlock;
1682 }
1683
1684 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001685 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001686 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001687 goto unlock;
1688 }
1689
1690 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001691
1692unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001693 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001694 return err;
1695}
1696
Johan Hedberg92da6092013-03-15 17:06:55 -05001697static void set_class_complete(struct hci_dev *hdev, u8 status)
1698{
1699 BT_DBG("status 0x%02x", status);
1700
1701 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1702}
1703
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001704static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001705 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001706{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001707 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001708 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001709 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001710 int err;
1711
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001712 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001713
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001714 if (!lmp_bredr_capable(hdev))
1715 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1716 MGMT_STATUS_NOT_SUPPORTED);
1717
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001718 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001719
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001720 if (pending_eir_or_class(hdev)) {
1721 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1722 MGMT_STATUS_BUSY);
1723 goto unlock;
1724 }
1725
1726 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1727 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1728 MGMT_STATUS_INVALID_PARAMS);
1729 goto unlock;
1730 }
1731
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001732 hdev->major_class = cp->major;
1733 hdev->minor_class = cp->minor;
1734
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001735 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001736 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001737 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001738 goto unlock;
1739 }
1740
Johan Hedberg890ea892013-03-15 17:06:52 -05001741 hci_req_init(&req, hdev);
1742
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001743 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001744 hci_dev_unlock(hdev);
1745 cancel_delayed_work_sync(&hdev->service_cache);
1746 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001747 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001748 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001749
Johan Hedberg890ea892013-03-15 17:06:52 -05001750 update_class(&req);
1751
Johan Hedberg92da6092013-03-15 17:06:55 -05001752 err = hci_req_run(&req, set_class_complete);
1753 if (err < 0) {
1754 if (err != -ENODATA)
1755 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001756
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001757 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001758 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001759 goto unlock;
1760 }
1761
1762 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001763 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001764 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001765 goto unlock;
1766 }
1767
1768 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001769
Johan Hedbergb5235a62012-02-21 14:32:24 +02001770unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001771 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001772 return err;
1773}
1774
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001775static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001776 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001777{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001778 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001779 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001780 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001781
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001782 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001783
Johan Hedberg86742e12011-11-07 23:13:38 +02001784 expected_len = sizeof(*cp) + key_count *
1785 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001786 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001787 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001788 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001789 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001790 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001791 }
1792
Johan Hedberg4ae14302013-01-20 14:27:13 +02001793 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1794 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1795 MGMT_STATUS_INVALID_PARAMS);
1796
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001797 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001798 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001799
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001800 for (i = 0; i < key_count; i++) {
1801 struct mgmt_link_key_info *key = &cp->keys[i];
1802
1803 if (key->addr.type != BDADDR_BREDR)
1804 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1805 MGMT_STATUS_INVALID_PARAMS);
1806 }
1807
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001808 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001809
1810 hci_link_keys_clear(hdev);
1811
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001812 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001813 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001814 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001815 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001816
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001817 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001818 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001819
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001820 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001821 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001822 }
1823
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001824 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001825
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001826 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001827
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001828 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001829}
1830
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001831static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001832 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001833{
1834 struct mgmt_ev_device_unpaired ev;
1835
1836 bacpy(&ev.addr.bdaddr, bdaddr);
1837 ev.addr.type = addr_type;
1838
1839 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001840 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001841}
1842
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001843static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001844 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001845{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001846 struct mgmt_cp_unpair_device *cp = data;
1847 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001848 struct hci_cp_disconnect dc;
1849 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001850 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001851 int err;
1852
Johan Hedberga8a1d192011-11-10 15:54:38 +02001853 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001854 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1855 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001856
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001857 if (!bdaddr_type_is_valid(cp->addr.type))
1858 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1859 MGMT_STATUS_INVALID_PARAMS,
1860 &rp, sizeof(rp));
1861
Johan Hedberg118da702013-01-20 14:27:20 +02001862 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1863 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1864 MGMT_STATUS_INVALID_PARAMS,
1865 &rp, sizeof(rp));
1866
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001867 hci_dev_lock(hdev);
1868
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001869 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001870 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001871 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001872 goto unlock;
1873 }
1874
Andre Guedes591f47f2012-04-24 21:02:49 -03001875 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001876 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1877 else
1878 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001879
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001880 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001881 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001882 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001883 goto unlock;
1884 }
1885
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001886 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001887 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001888 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001889 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001890 else
1891 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001892 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001893 } else {
1894 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001895 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001896
Johan Hedberga8a1d192011-11-10 15:54:38 +02001897 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001898 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001899 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001900 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001901 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001902 }
1903
Johan Hedberg124f6e32012-02-09 13:50:12 +02001904 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001905 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001906 if (!cmd) {
1907 err = -ENOMEM;
1908 goto unlock;
1909 }
1910
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001911 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001912 dc.reason = 0x13; /* Remote User Terminated Connection */
1913 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1914 if (err < 0)
1915 mgmt_pending_remove(cmd);
1916
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001917unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001918 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001919 return err;
1920}
1921
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001922static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001923 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001924{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001925 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001926 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001927 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001928 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001929 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001930 int err;
1931
1932 BT_DBG("");
1933
Johan Hedberg06a63b12013-01-20 14:27:21 +02001934 memset(&rp, 0, sizeof(rp));
1935 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1936 rp.addr.type = cp->addr.type;
1937
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001938 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001939 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1940 MGMT_STATUS_INVALID_PARAMS,
1941 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001942
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001943 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001944
1945 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001946 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1947 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001948 goto failed;
1949 }
1950
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001951 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001952 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1953 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001954 goto failed;
1955 }
1956
Andre Guedes591f47f2012-04-24 21:02:49 -03001957 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001958 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1959 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001960 else
1961 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001962
Vishal Agarwalf9607272012-06-13 05:32:43 +05301963 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001964 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1965 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001966 goto failed;
1967 }
1968
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001969 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001970 if (!cmd) {
1971 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001972 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001973 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001974
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001975 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001976 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001977
1978 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1979 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001980 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001981
1982failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001983 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001984 return err;
1985}
1986
Andre Guedes57c14772012-04-24 21:02:50 -03001987static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001988{
1989 switch (link_type) {
1990 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001991 switch (addr_type) {
1992 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001993 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001994
Johan Hedberg48264f02011-11-09 13:58:58 +02001995 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001996 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001997 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001998 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001999
Johan Hedberg4c659c32011-11-07 23:13:39 +02002000 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002001 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002002 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002003 }
2004}
2005
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002006static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2007 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002008{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002009 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002010 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002011 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002012 int err;
2013 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002014
2015 BT_DBG("");
2016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002017 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002018
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002019 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002020 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002021 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002022 goto unlock;
2023 }
2024
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002025 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002026 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2027 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002028 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002029 }
2030
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002031 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002032 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002033 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002034 err = -ENOMEM;
2035 goto unlock;
2036 }
2037
Johan Hedberg2784eb42011-01-21 13:56:35 +02002038 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002039 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002040 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2041 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002042 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002043 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002044 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002045 continue;
2046 i++;
2047 }
2048
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002049 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002050
Johan Hedberg4c659c32011-11-07 23:13:39 +02002051 /* Recalculate length in case of filtered SCO connections, etc */
2052 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002054 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002055 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002056
Johan Hedberga38528f2011-01-22 06:46:43 +02002057 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002058
2059unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002060 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002061 return err;
2062}
2063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002064static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002065 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002066{
2067 struct pending_cmd *cmd;
2068 int err;
2069
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002070 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002071 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002072 if (!cmd)
2073 return -ENOMEM;
2074
Johan Hedbergd8457692012-02-17 14:24:57 +02002075 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002076 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002077 if (err < 0)
2078 mgmt_pending_remove(cmd);
2079
2080 return err;
2081}
2082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002084 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002085{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002086 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002087 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002088 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002089 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002090 int err;
2091
2092 BT_DBG("");
2093
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002094 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002095
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002096 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002099 goto failed;
2100 }
2101
Johan Hedbergd8457692012-02-17 14:24:57 +02002102 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002103 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002104 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002105 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002106 goto failed;
2107 }
2108
2109 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002110 struct mgmt_cp_pin_code_neg_reply ncp;
2111
2112 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002113
2114 BT_ERR("PIN code is not 16 bytes long");
2115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002117 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002118 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002119 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002120
2121 goto failed;
2122 }
2123
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002124 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002125 if (!cmd) {
2126 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002127 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002128 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002129
Johan Hedbergd8457692012-02-17 14:24:57 +02002130 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002131 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002132 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002133
2134 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2135 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002136 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002137
2138failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002139 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140 return err;
2141}
2142
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002143static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2144 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002145{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002146 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002147
2148 BT_DBG("");
2149
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002150 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002151
2152 hdev->io_capability = cp->io_capability;
2153
2154 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002155 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002156
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002157 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002158
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002159 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2160 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002161}
2162
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002163static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002164{
2165 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002166 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002167
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002168 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002169 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2170 continue;
2171
Johan Hedberge9a416b2011-02-19 12:05:56 -03002172 if (cmd->user_data != conn)
2173 continue;
2174
2175 return cmd;
2176 }
2177
2178 return NULL;
2179}
2180
2181static void pairing_complete(struct pending_cmd *cmd, u8 status)
2182{
2183 struct mgmt_rp_pair_device rp;
2184 struct hci_conn *conn = cmd->user_data;
2185
Johan Hedbergba4e5642011-11-11 00:07:34 +02002186 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002187 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002188
Johan Hedbergaee9b212012-02-18 15:07:59 +02002189 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002191
2192 /* So we don't get further callbacks for this connection */
2193 conn->connect_cfm_cb = NULL;
2194 conn->security_cfm_cb = NULL;
2195 conn->disconn_cfm_cb = NULL;
2196
David Herrmann76a68ba2013-04-06 20:28:37 +02002197 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002198
Johan Hedberga664b5b2011-02-19 12:06:02 -03002199 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002200}
2201
2202static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2203{
2204 struct pending_cmd *cmd;
2205
2206 BT_DBG("status %u", status);
2207
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002208 cmd = find_pairing(conn);
2209 if (!cmd)
2210 BT_DBG("Unable to find a pending command");
2211 else
Johan Hedberge2113262012-02-18 15:20:03 +02002212 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002213}
2214
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302215static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2216{
2217 struct pending_cmd *cmd;
2218
2219 BT_DBG("status %u", status);
2220
2221 if (!status)
2222 return;
2223
2224 cmd = find_pairing(conn);
2225 if (!cmd)
2226 BT_DBG("Unable to find a pending command");
2227 else
2228 pairing_complete(cmd, mgmt_status(status));
2229}
2230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002232 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002233{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002234 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002235 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002236 struct pending_cmd *cmd;
2237 u8 sec_level, auth_type;
2238 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002239 int err;
2240
2241 BT_DBG("");
2242
Szymon Jancf950a30e2013-01-18 12:48:07 +01002243 memset(&rp, 0, sizeof(rp));
2244 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2245 rp.addr.type = cp->addr.type;
2246
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002247 if (!bdaddr_type_is_valid(cp->addr.type))
2248 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2249 MGMT_STATUS_INVALID_PARAMS,
2250 &rp, sizeof(rp));
2251
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002252 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002253
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002254 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002255 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2256 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002257 goto unlock;
2258 }
2259
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002260 sec_level = BT_SECURITY_MEDIUM;
2261 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002262 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002263 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002264 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002265
Andre Guedes591f47f2012-04-24 21:02:49 -03002266 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002267 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2268 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002269 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002270 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2271 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002272
Ville Tervo30e76272011-02-22 16:10:53 -03002273 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002274 int status;
2275
2276 if (PTR_ERR(conn) == -EBUSY)
2277 status = MGMT_STATUS_BUSY;
2278 else
2279 status = MGMT_STATUS_CONNECT_FAILED;
2280
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002281 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002282 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002283 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002284 goto unlock;
2285 }
2286
2287 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002288 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002289 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002290 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002291 goto unlock;
2292 }
2293
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002294 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002295 if (!cmd) {
2296 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002297 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002298 goto unlock;
2299 }
2300
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002301 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002302 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002303 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302304 else
2305 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002306
Johan Hedberge9a416b2011-02-19 12:05:56 -03002307 conn->security_cfm_cb = pairing_complete_cb;
2308 conn->disconn_cfm_cb = pairing_complete_cb;
2309 conn->io_capability = cp->io_cap;
2310 cmd->user_data = conn;
2311
2312 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002313 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002314 pairing_complete(cmd, 0);
2315
2316 err = 0;
2317
2318unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002319 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002320 return err;
2321}
2322
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2324 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002325{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002326 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002327 struct pending_cmd *cmd;
2328 struct hci_conn *conn;
2329 int err;
2330
2331 BT_DBG("");
2332
Johan Hedberg28424702012-02-02 04:02:29 +02002333 hci_dev_lock(hdev);
2334
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002335 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002336 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002337 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002338 goto unlock;
2339 }
2340
Johan Hedberg28424702012-02-02 04:02:29 +02002341 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2342 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002343 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002344 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002345 goto unlock;
2346 }
2347
2348 conn = cmd->user_data;
2349
2350 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002351 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002352 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002353 goto unlock;
2354 }
2355
2356 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2357
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002358 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002359 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002360unlock:
2361 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002362 return err;
2363}
2364
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002365static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002366 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002367 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002368{
Johan Hedberga5c29682011-02-19 12:05:57 -03002369 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002370 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002371 int err;
2372
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002373 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002374
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002375 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002376 err = cmd_complete(sk, hdev->id, mgmt_op,
2377 MGMT_STATUS_NOT_POWERED, addr,
2378 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002379 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002380 }
2381
Johan Hedberg1707c602013-03-15 17:07:15 -05002382 if (addr->type == BDADDR_BREDR)
2383 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002384 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002385 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002386
Johan Hedberg272d90d2012-02-09 15:26:12 +02002387 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002388 err = cmd_complete(sk, hdev->id, mgmt_op,
2389 MGMT_STATUS_NOT_CONNECTED, addr,
2390 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002391 goto done;
2392 }
2393
Johan Hedberg1707c602013-03-15 17:07:15 -05002394 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002395 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002396 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002397
Brian Gix5fe57d92011-12-21 16:12:13 -08002398 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002399 err = cmd_complete(sk, hdev->id, mgmt_op,
2400 MGMT_STATUS_SUCCESS, addr,
2401 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002402 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002403 err = cmd_complete(sk, hdev->id, mgmt_op,
2404 MGMT_STATUS_FAILED, addr,
2405 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002406
Brian Gix47c15e22011-11-16 13:53:14 -08002407 goto done;
2408 }
2409
Johan Hedberg1707c602013-03-15 17:07:15 -05002410 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002411 if (!cmd) {
2412 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002413 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002414 }
2415
Brian Gix0df4c182011-11-16 13:53:13 -08002416 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002417 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2418 struct hci_cp_user_passkey_reply cp;
2419
Johan Hedberg1707c602013-03-15 17:07:15 -05002420 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002421 cp.passkey = passkey;
2422 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2423 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002424 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2425 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002426
Johan Hedberga664b5b2011-02-19 12:06:02 -03002427 if (err < 0)
2428 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002429
Brian Gix0df4c182011-11-16 13:53:13 -08002430done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002431 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002432 return err;
2433}
2434
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302435static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2436 void *data, u16 len)
2437{
2438 struct mgmt_cp_pin_code_neg_reply *cp = data;
2439
2440 BT_DBG("");
2441
Johan Hedberg1707c602013-03-15 17:07:15 -05002442 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302443 MGMT_OP_PIN_CODE_NEG_REPLY,
2444 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2445}
2446
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002447static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2448 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002449{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002450 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002451
2452 BT_DBG("");
2453
2454 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002455 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002456 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002457
Johan Hedberg1707c602013-03-15 17:07:15 -05002458 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002459 MGMT_OP_USER_CONFIRM_REPLY,
2460 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002461}
2462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002463static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002464 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002465{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002466 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002467
2468 BT_DBG("");
2469
Johan Hedberg1707c602013-03-15 17:07:15 -05002470 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002471 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2472 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002473}
2474
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002475static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2476 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002477{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002478 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002479
2480 BT_DBG("");
2481
Johan Hedberg1707c602013-03-15 17:07:15 -05002482 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002483 MGMT_OP_USER_PASSKEY_REPLY,
2484 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002485}
2486
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002487static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002488 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002489{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002490 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002491
2492 BT_DBG("");
2493
Johan Hedberg1707c602013-03-15 17:07:15 -05002494 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002495 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2496 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002497}
2498
Johan Hedberg13928972013-03-15 17:07:00 -05002499static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002500{
Johan Hedberg13928972013-03-15 17:07:00 -05002501 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002502 struct hci_cp_write_local_name cp;
2503
Johan Hedberg13928972013-03-15 17:07:00 -05002504 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002505
Johan Hedberg890ea892013-03-15 17:06:52 -05002506 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002507}
2508
Johan Hedberg13928972013-03-15 17:07:00 -05002509static void set_name_complete(struct hci_dev *hdev, u8 status)
2510{
2511 struct mgmt_cp_set_local_name *cp;
2512 struct pending_cmd *cmd;
2513
2514 BT_DBG("status 0x%02x", status);
2515
2516 hci_dev_lock(hdev);
2517
2518 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2519 if (!cmd)
2520 goto unlock;
2521
2522 cp = cmd->param;
2523
2524 if (status)
2525 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2526 mgmt_status(status));
2527 else
2528 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2529 cp, sizeof(*cp));
2530
2531 mgmt_pending_remove(cmd);
2532
2533unlock:
2534 hci_dev_unlock(hdev);
2535}
2536
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002537static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002538 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002539{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002540 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002541 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002542 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002543 int err;
2544
2545 BT_DBG("");
2546
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002547 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002548
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002549 /* If the old values are the same as the new ones just return a
2550 * direct command complete event.
2551 */
2552 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2553 !memcmp(hdev->short_name, cp->short_name,
2554 sizeof(hdev->short_name))) {
2555 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2556 data, len);
2557 goto failed;
2558 }
2559
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002560 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002561
Johan Hedbergb5235a62012-02-21 14:32:24 +02002562 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002563 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002564
2565 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002567 if (err < 0)
2568 goto failed;
2569
2570 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002571 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002572
Johan Hedbergb5235a62012-02-21 14:32:24 +02002573 goto failed;
2574 }
2575
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002576 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002577 if (!cmd) {
2578 err = -ENOMEM;
2579 goto failed;
2580 }
2581
Johan Hedberg13928972013-03-15 17:07:00 -05002582 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2583
Johan Hedberg890ea892013-03-15 17:06:52 -05002584 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002585
2586 if (lmp_bredr_capable(hdev)) {
2587 update_name(&req);
2588 update_eir(&req);
2589 }
2590
2591 if (lmp_le_capable(hdev))
2592 hci_update_ad(&req);
2593
Johan Hedberg13928972013-03-15 17:07:00 -05002594 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002595 if (err < 0)
2596 mgmt_pending_remove(cmd);
2597
2598failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002599 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002600 return err;
2601}
2602
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002603static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002604 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002605{
Szymon Jancc35938b2011-03-22 13:12:21 +01002606 struct pending_cmd *cmd;
2607 int err;
2608
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002609 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002610
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002611 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002612
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002613 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002614 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002615 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002616 goto unlock;
2617 }
2618
Andre Guedes9a1a1992012-07-24 15:03:48 -03002619 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002620 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002621 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002622 goto unlock;
2623 }
2624
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002625 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002627 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002628 goto unlock;
2629 }
2630
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002631 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002632 if (!cmd) {
2633 err = -ENOMEM;
2634 goto unlock;
2635 }
2636
2637 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2638 if (err < 0)
2639 mgmt_pending_remove(cmd);
2640
2641unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002642 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002643 return err;
2644}
2645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002646static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002647 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002648{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002649 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002650 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002651 int err;
2652
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002653 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002655 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002656
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002657 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002658 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002659 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002660 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002661 else
Szymon Janca6785be2012-12-13 15:11:21 +01002662 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002664 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002665 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002666
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002667 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002668 return err;
2669}
2670
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002671static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002672 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002673{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002674 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002675 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002676 int err;
2677
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002678 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002679
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002680 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002681
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002682 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002683 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002684 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002685 else
Szymon Janca6785be2012-12-13 15:11:21 +01002686 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002688 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002689 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002690
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002691 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002692 return err;
2693}
2694
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002695static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2696{
2697 struct pending_cmd *cmd;
2698 u8 type;
2699 int err;
2700
2701 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2702
2703 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2704 if (!cmd)
2705 return -ENOENT;
2706
2707 type = hdev->discovery.type;
2708
2709 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2710 &type, sizeof(type));
2711 mgmt_pending_remove(cmd);
2712
2713 return err;
2714}
2715
Andre Guedes7c307722013-04-30 15:29:28 -03002716static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2717{
2718 BT_DBG("status %d", status);
2719
2720 if (status) {
2721 hci_dev_lock(hdev);
2722 mgmt_start_discovery_failed(hdev, status);
2723 hci_dev_unlock(hdev);
2724 return;
2725 }
2726
2727 hci_dev_lock(hdev);
2728 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2729 hci_dev_unlock(hdev);
2730
2731 switch (hdev->discovery.type) {
2732 case DISCOV_TYPE_LE:
2733 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002734 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002735 break;
2736
2737 case DISCOV_TYPE_INTERLEAVED:
2738 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002739 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002740 break;
2741
2742 case DISCOV_TYPE_BREDR:
2743 break;
2744
2745 default:
2746 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2747 }
2748}
2749
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002750static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002751 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002752{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002753 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002754 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002755 struct hci_cp_le_set_scan_param param_cp;
2756 struct hci_cp_le_set_scan_enable enable_cp;
2757 struct hci_cp_inquiry inq_cp;
2758 struct hci_request req;
2759 /* General inquiry access code (GIAC) */
2760 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002761 int err;
2762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002763 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002765 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002766
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002767 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002768 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002769 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002770 goto failed;
2771 }
2772
Andre Guedes642be6c2012-03-21 00:03:37 -03002773 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2774 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2775 MGMT_STATUS_BUSY);
2776 goto failed;
2777 }
2778
Johan Hedbergff9ef572012-01-04 14:23:45 +02002779 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002780 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002781 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002782 goto failed;
2783 }
2784
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002785 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002786 if (!cmd) {
2787 err = -ENOMEM;
2788 goto failed;
2789 }
2790
Andre Guedes4aab14e2012-02-17 20:39:36 -03002791 hdev->discovery.type = cp->type;
2792
Andre Guedes7c307722013-04-30 15:29:28 -03002793 hci_req_init(&req, hdev);
2794
Andre Guedes4aab14e2012-02-17 20:39:36 -03002795 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002796 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002797 if (!lmp_bredr_capable(hdev)) {
2798 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2799 MGMT_STATUS_NOT_SUPPORTED);
2800 mgmt_pending_remove(cmd);
2801 goto failed;
2802 }
2803
Andre Guedes7c307722013-04-30 15:29:28 -03002804 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2805 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2806 MGMT_STATUS_BUSY);
2807 mgmt_pending_remove(cmd);
2808 goto failed;
2809 }
2810
2811 hci_inquiry_cache_flush(hdev);
2812
2813 memset(&inq_cp, 0, sizeof(inq_cp));
2814 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002815 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002816 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002817 break;
2818
2819 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002820 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002821 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002822 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2823 MGMT_STATUS_NOT_SUPPORTED);
2824 mgmt_pending_remove(cmd);
2825 goto failed;
2826 }
2827
Andre Guedes7c307722013-04-30 15:29:28 -03002828 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
2829 !lmp_bredr_capable(hdev)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002830 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2831 MGMT_STATUS_NOT_SUPPORTED);
2832 mgmt_pending_remove(cmd);
2833 goto failed;
2834 }
2835
Andre Guedes7c307722013-04-30 15:29:28 -03002836 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2837 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2838 MGMT_STATUS_REJECTED);
2839 mgmt_pending_remove(cmd);
2840 goto failed;
2841 }
2842
2843 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2844 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2845 MGMT_STATUS_BUSY);
2846 mgmt_pending_remove(cmd);
2847 goto failed;
2848 }
2849
2850 memset(&param_cp, 0, sizeof(param_cp));
2851 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002852 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2853 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002854 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2855 &param_cp);
2856
2857 memset(&enable_cp, 0, sizeof(enable_cp));
2858 enable_cp.enable = LE_SCAN_ENABLE;
2859 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2860 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2861 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002862 break;
2863
Andre Guedesf39799f2012-02-17 20:39:35 -03002864 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002865 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2866 MGMT_STATUS_INVALID_PARAMS);
2867 mgmt_pending_remove(cmd);
2868 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002869 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002870
Andre Guedes7c307722013-04-30 15:29:28 -03002871 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002872 if (err < 0)
2873 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002874 else
2875 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002876
2877failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002878 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002879 return err;
2880}
2881
Andre Guedes1183fdc2013-04-30 15:29:35 -03002882static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2883{
2884 struct pending_cmd *cmd;
2885 int err;
2886
2887 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2888 if (!cmd)
2889 return -ENOENT;
2890
2891 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2892 &hdev->discovery.type, sizeof(hdev->discovery.type));
2893 mgmt_pending_remove(cmd);
2894
2895 return err;
2896}
2897
Andre Guedes0e05bba2013-04-30 15:29:33 -03002898static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2899{
2900 BT_DBG("status %d", status);
2901
2902 hci_dev_lock(hdev);
2903
2904 if (status) {
2905 mgmt_stop_discovery_failed(hdev, status);
2906 goto unlock;
2907 }
2908
2909 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2910
2911unlock:
2912 hci_dev_unlock(hdev);
2913}
2914
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002915static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002916 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002917{
Johan Hedbergd9306502012-02-20 23:25:18 +02002918 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002919 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002920 struct hci_cp_remote_name_req_cancel cp;
2921 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002922 struct hci_request req;
2923 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002924 int err;
2925
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002926 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002928 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002929
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002930 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002931 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002932 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2933 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002934 goto unlock;
2935 }
2936
2937 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002938 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002939 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2940 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002941 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002942 }
2943
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002944 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002945 if (!cmd) {
2946 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002947 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002948 }
2949
Andre Guedes0e05bba2013-04-30 15:29:33 -03002950 hci_req_init(&req, hdev);
2951
Andre Guedese0d9727e2012-03-20 15:15:36 -03002952 switch (hdev->discovery.state) {
2953 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002954 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2955 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2956 } else {
2957 cancel_delayed_work(&hdev->le_scan_disable);
2958
2959 memset(&enable_cp, 0, sizeof(enable_cp));
2960 enable_cp.enable = LE_SCAN_DISABLE;
2961 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2962 sizeof(enable_cp), &enable_cp);
2963 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002964
Andre Guedese0d9727e2012-03-20 15:15:36 -03002965 break;
2966
2967 case DISCOVERY_RESOLVING:
2968 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002969 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002970 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002971 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002972 err = cmd_complete(sk, hdev->id,
2973 MGMT_OP_STOP_DISCOVERY, 0,
2974 &mgmt_cp->type,
2975 sizeof(mgmt_cp->type));
2976 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2977 goto unlock;
2978 }
2979
2980 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002981 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2982 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002983
2984 break;
2985
2986 default:
2987 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002988
2989 mgmt_pending_remove(cmd);
2990 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
2991 MGMT_STATUS_FAILED, &mgmt_cp->type,
2992 sizeof(mgmt_cp->type));
2993 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002994 }
2995
Andre Guedes0e05bba2013-04-30 15:29:33 -03002996 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002997 if (err < 0)
2998 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002999 else
3000 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003001
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003002unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003003 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003004 return err;
3005}
3006
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003007static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003008 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003009{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003010 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003011 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003012 int err;
3013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003014 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003015
Johan Hedberg561aafb2012-01-04 13:31:59 +02003016 hci_dev_lock(hdev);
3017
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003018 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003019 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003020 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003021 goto failed;
3022 }
3023
Johan Hedberga198e7b2012-02-17 14:27:06 +02003024 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003025 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003026 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003027 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003028 goto failed;
3029 }
3030
3031 if (cp->name_known) {
3032 e->name_state = NAME_KNOWN;
3033 list_del(&e->list);
3034 } else {
3035 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003036 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003037 }
3038
Johan Hedberge3846622013-01-09 15:29:33 +02003039 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3040 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003041
3042failed:
3043 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003044 return err;
3045}
3046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003047static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003048 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003049{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003050 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003051 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003052 int err;
3053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003054 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003055
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003056 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003057 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3058 MGMT_STATUS_INVALID_PARAMS,
3059 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003060
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003061 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003062
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003063 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003064 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003065 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003066 else
Szymon Janca6785be2012-12-13 15:11:21 +01003067 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003068
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003069 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003070 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003071
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003072 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003073
3074 return err;
3075}
3076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003077static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003078 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003079{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003080 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003081 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003082 int err;
3083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003084 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003085
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003086 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003087 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3088 MGMT_STATUS_INVALID_PARAMS,
3089 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003090
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003091 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003092
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003093 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003094 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003095 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003096 else
Szymon Janca6785be2012-12-13 15:11:21 +01003097 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003099 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003100 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003101
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003102 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003103
3104 return err;
3105}
3106
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003107static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3108 u16 len)
3109{
3110 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003111 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003112 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003113 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003114
3115 BT_DBG("%s", hdev->name);
3116
Szymon Jancc72d4b82012-03-16 16:02:57 +01003117 source = __le16_to_cpu(cp->source);
3118
3119 if (source > 0x0002)
3120 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3121 MGMT_STATUS_INVALID_PARAMS);
3122
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003123 hci_dev_lock(hdev);
3124
Szymon Jancc72d4b82012-03-16 16:02:57 +01003125 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003126 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3127 hdev->devid_product = __le16_to_cpu(cp->product);
3128 hdev->devid_version = __le16_to_cpu(cp->version);
3129
3130 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3131
Johan Hedberg890ea892013-03-15 17:06:52 -05003132 hci_req_init(&req, hdev);
3133 update_eir(&req);
3134 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003135
3136 hci_dev_unlock(hdev);
3137
3138 return err;
3139}
3140
Johan Hedberg4375f102013-09-25 13:26:10 +03003141static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3142{
3143 struct cmd_lookup match = { NULL, hdev };
3144
3145 if (status) {
3146 u8 mgmt_err = mgmt_status(status);
3147
3148 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3149 cmd_status_rsp, &mgmt_err);
3150 return;
3151 }
3152
3153 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3154 &match);
3155
3156 new_settings(hdev, match.sk);
3157
3158 if (match.sk)
3159 sock_put(match.sk);
3160}
3161
3162static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3163{
3164 struct mgmt_mode *cp = data;
3165 struct pending_cmd *cmd;
3166 struct hci_request req;
3167 u8 val, enabled;
3168 int err;
3169
3170 BT_DBG("request for %s", hdev->name);
3171
3172 if (!lmp_le_capable(hdev))
3173 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3174 MGMT_STATUS_NOT_SUPPORTED);
3175
3176 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3177 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3178 MGMT_STATUS_REJECTED);
3179
3180 if (cp->val != 0x00 && cp->val != 0x01)
3181 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3182 MGMT_STATUS_INVALID_PARAMS);
3183
3184 hci_dev_lock(hdev);
3185
3186 val = !!cp->val;
3187 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3188
3189 if (!hdev_is_powered(hdev) || val == enabled) {
3190 bool changed = false;
3191
3192 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3193 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3194 changed = true;
3195 }
3196
3197 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3198 if (err < 0)
3199 goto unlock;
3200
3201 if (changed)
3202 err = new_settings(hdev, sk);
3203
3204 goto unlock;
3205 }
3206
3207 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3208 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3209 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3210 MGMT_STATUS_BUSY);
3211 goto unlock;
3212 }
3213
3214 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3215 if (!cmd) {
3216 err = -ENOMEM;
3217 goto unlock;
3218 }
3219
3220 hci_req_init(&req, hdev);
3221
3222 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3223
3224 err = hci_req_run(&req, set_advertising_complete);
3225 if (err < 0)
3226 mgmt_pending_remove(cmd);
3227
3228unlock:
3229 hci_dev_unlock(hdev);
3230 return err;
3231}
3232
Johan Hedberg33e38b32013-03-15 17:07:05 -05003233static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3234{
3235 struct pending_cmd *cmd;
3236
3237 BT_DBG("status 0x%02x", status);
3238
3239 hci_dev_lock(hdev);
3240
3241 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3242 if (!cmd)
3243 goto unlock;
3244
3245 if (status) {
3246 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3247 mgmt_status(status));
3248 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003249 struct mgmt_mode *cp = cmd->param;
3250
3251 if (cp->val)
3252 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3253 else
3254 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3255
Johan Hedberg33e38b32013-03-15 17:07:05 -05003256 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3257 new_settings(hdev, cmd->sk);
3258 }
3259
3260 mgmt_pending_remove(cmd);
3261
3262unlock:
3263 hci_dev_unlock(hdev);
3264}
3265
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003266static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003267 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003268{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003269 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003270 struct pending_cmd *cmd;
3271 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003272 int err;
3273
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003274 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003275
Johan Hedberg1a47aee2013-03-15 17:07:06 -05003276 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003277 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3278 MGMT_STATUS_NOT_SUPPORTED);
3279
Johan Hedberga7e80f22013-01-09 16:05:19 +02003280 if (cp->val != 0x00 && cp->val != 0x01)
3281 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3282 MGMT_STATUS_INVALID_PARAMS);
3283
Johan Hedberg5400c042012-02-21 16:40:33 +02003284 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003285 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003286 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003287
3288 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003289 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003290 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003291
3292 hci_dev_lock(hdev);
3293
Johan Hedberg05cbf292013-03-15 17:07:07 -05003294 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3295 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3296 MGMT_STATUS_BUSY);
3297 goto unlock;
3298 }
3299
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003300 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3301 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3302 hdev);
3303 goto unlock;
3304 }
3305
Johan Hedberg33e38b32013-03-15 17:07:05 -05003306 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3307 data, len);
3308 if (!cmd) {
3309 err = -ENOMEM;
3310 goto unlock;
3311 }
3312
3313 hci_req_init(&req, hdev);
3314
Johan Hedberg406d7802013-03-15 17:07:09 -05003315 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003316
3317 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003318 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003319 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003320 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003321 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003322 }
3323
Johan Hedberg33e38b32013-03-15 17:07:05 -05003324unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003325 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003326
Antti Julkuf6422ec2011-06-22 13:11:56 +03003327 return err;
3328}
3329
Johan Hedberg3f706b72013-01-20 14:27:16 +02003330static bool ltk_is_valid(struct mgmt_ltk_info *key)
3331{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003332 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3333 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003334 if (key->master != 0x00 && key->master != 0x01)
3335 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003336 if (!bdaddr_type_is_le(key->addr.type))
3337 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003338 return true;
3339}
3340
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003341static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003342 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003343{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003344 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3345 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003346 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003347
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003348 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003349
3350 expected_len = sizeof(*cp) + key_count *
3351 sizeof(struct mgmt_ltk_info);
3352 if (expected_len != len) {
3353 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003354 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003355 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003356 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003357 }
3358
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003359 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003360
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003361 for (i = 0; i < key_count; i++) {
3362 struct mgmt_ltk_info *key = &cp->keys[i];
3363
Johan Hedberg3f706b72013-01-20 14:27:16 +02003364 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003365 return cmd_status(sk, hdev->id,
3366 MGMT_OP_LOAD_LONG_TERM_KEYS,
3367 MGMT_STATUS_INVALID_PARAMS);
3368 }
3369
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003370 hci_dev_lock(hdev);
3371
3372 hci_smp_ltks_clear(hdev);
3373
3374 for (i = 0; i < key_count; i++) {
3375 struct mgmt_ltk_info *key = &cp->keys[i];
3376 u8 type;
3377
3378 if (key->master)
3379 type = HCI_SMP_LTK;
3380 else
3381 type = HCI_SMP_LTK_SLAVE;
3382
Hemant Gupta4596fde2012-04-16 14:57:40 +05303383 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003384 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003385 type, 0, key->authenticated, key->val,
3386 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003387 }
3388
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003389 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3390 NULL, 0);
3391
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003392 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003393
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003394 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003395}
3396
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003397static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003398 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3399 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003400 bool var_len;
3401 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003402} mgmt_handlers[] = {
3403 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003404 { read_version, false, MGMT_READ_VERSION_SIZE },
3405 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3406 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3407 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3408 { set_powered, false, MGMT_SETTING_SIZE },
3409 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3410 { set_connectable, false, MGMT_SETTING_SIZE },
3411 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3412 { set_pairable, false, MGMT_SETTING_SIZE },
3413 { set_link_security, false, MGMT_SETTING_SIZE },
3414 { set_ssp, false, MGMT_SETTING_SIZE },
3415 { set_hs, false, MGMT_SETTING_SIZE },
3416 { set_le, false, MGMT_SETTING_SIZE },
3417 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3418 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3419 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3420 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3421 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3422 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3423 { disconnect, false, MGMT_DISCONNECT_SIZE },
3424 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3425 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3426 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3427 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3428 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3429 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3430 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3431 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3432 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3433 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3434 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3435 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3436 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3437 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3438 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3439 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3440 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3441 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3442 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003443 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003444 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003445};
3446
3447
Johan Hedberg03811012010-12-08 00:21:06 +02003448int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3449{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003450 void *buf;
3451 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003452 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003453 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003454 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003455 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003456 int err;
3457
3458 BT_DBG("got %zu bytes", msglen);
3459
3460 if (msglen < sizeof(*hdr))
3461 return -EINVAL;
3462
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003463 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003464 if (!buf)
3465 return -ENOMEM;
3466
3467 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3468 err = -EFAULT;
3469 goto done;
3470 }
3471
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003472 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003473 opcode = __le16_to_cpu(hdr->opcode);
3474 index = __le16_to_cpu(hdr->index);
3475 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003476
3477 if (len != msglen - sizeof(*hdr)) {
3478 err = -EINVAL;
3479 goto done;
3480 }
3481
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003482 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003483 hdev = hci_dev_get(index);
3484 if (!hdev) {
3485 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003486 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003487 goto done;
3488 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003489
3490 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3491 err = cmd_status(sk, index, opcode,
3492 MGMT_STATUS_INVALID_INDEX);
3493 goto done;
3494 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003495 }
3496
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003497 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003498 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003499 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003500 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003501 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003502 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003503 }
3504
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003505 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003506 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003507 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003508 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003509 goto done;
3510 }
3511
Johan Hedbergbe22b542012-03-01 22:24:41 +02003512 handler = &mgmt_handlers[opcode];
3513
3514 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003515 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003516 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003517 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003518 goto done;
3519 }
3520
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003521 if (hdev)
3522 mgmt_init_hdev(sk, hdev);
3523
3524 cp = buf + sizeof(*hdr);
3525
Johan Hedbergbe22b542012-03-01 22:24:41 +02003526 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003527 if (err < 0)
3528 goto done;
3529
Johan Hedberg03811012010-12-08 00:21:06 +02003530 err = msglen;
3531
3532done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003533 if (hdev)
3534 hci_dev_put(hdev);
3535
Johan Hedberg03811012010-12-08 00:21:06 +02003536 kfree(buf);
3537 return err;
3538}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003539
Johan Hedberg744cf192011-11-08 20:40:14 +02003540int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003541{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003542 if (!mgmt_valid_hdev(hdev))
3543 return -ENOTSUPP;
3544
Johan Hedberg744cf192011-11-08 20:40:14 +02003545 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003546}
3547
Johan Hedberg744cf192011-11-08 20:40:14 +02003548int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003549{
Johan Hedberg5f159032012-03-02 03:13:19 +02003550 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003551
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003552 if (!mgmt_valid_hdev(hdev))
3553 return -ENOTSUPP;
3554
Johan Hedberg744cf192011-11-08 20:40:14 +02003555 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003556
Johan Hedberg744cf192011-11-08 20:40:14 +02003557 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003558}
3559
Johan Hedberg890ea892013-03-15 17:06:52 -05003560static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003561{
Johan Hedberg890ea892013-03-15 17:06:52 -05003562 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003563 u8 scan = 0;
3564
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003565 /* Ensure that fast connectable is disabled. This function will
3566 * not do anything if the page scan parameters are already what
3567 * they should be.
3568 */
3569 write_fast_connectable(req, false);
3570
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003571 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3572 scan |= SCAN_PAGE;
3573 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3574 scan |= SCAN_INQUIRY;
3575
Johan Hedberg890ea892013-03-15 17:06:52 -05003576 if (scan)
3577 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003578}
3579
Johan Hedberg229ab392013-03-15 17:06:53 -05003580static void powered_complete(struct hci_dev *hdev, u8 status)
3581{
3582 struct cmd_lookup match = { NULL, hdev };
3583
3584 BT_DBG("status 0x%02x", status);
3585
3586 hci_dev_lock(hdev);
3587
3588 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3589
3590 new_settings(hdev, match.sk);
3591
3592 hci_dev_unlock(hdev);
3593
3594 if (match.sk)
3595 sock_put(match.sk);
3596}
3597
Johan Hedberg70da6242013-03-15 17:06:51 -05003598static int powered_update_hci(struct hci_dev *hdev)
3599{
Johan Hedberg890ea892013-03-15 17:06:52 -05003600 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003601 u8 link_sec;
3602
Johan Hedberg890ea892013-03-15 17:06:52 -05003603 hci_req_init(&req, hdev);
3604
Johan Hedberg70da6242013-03-15 17:06:51 -05003605 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3606 !lmp_host_ssp_capable(hdev)) {
3607 u8 ssp = 1;
3608
Johan Hedberg890ea892013-03-15 17:06:52 -05003609 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003610 }
3611
Johan Hedbergc73eee92013-04-19 18:35:21 +03003612 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3613 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003614 struct hci_cp_write_le_host_supported cp;
3615
3616 cp.le = 1;
3617 cp.simul = lmp_le_br_capable(hdev);
3618
3619 /* Check first if we already have the right
3620 * host state (host features set)
3621 */
3622 if (cp.le != lmp_host_le_capable(hdev) ||
3623 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003624 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3625 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003626 }
3627
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003628 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3629 u8 adv = 0x01;
3630
3631 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3632 }
3633
Johan Hedberg70da6242013-03-15 17:06:51 -05003634 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3635 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003636 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3637 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003638
3639 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003640 set_bredr_scan(&req);
3641 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003642 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003643 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003644 }
3645
Johan Hedberg229ab392013-03-15 17:06:53 -05003646 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003647}
3648
Johan Hedberg744cf192011-11-08 20:40:14 +02003649int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003650{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003651 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003652 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3653 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003654 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003655
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003656 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3657 return 0;
3658
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003659 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003660 if (powered_update_hci(hdev) == 0)
3661 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003662
Johan Hedberg229ab392013-03-15 17:06:53 -05003663 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3664 &match);
3665 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003666 }
3667
Johan Hedberg229ab392013-03-15 17:06:53 -05003668 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3669 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3670
3671 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3672 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3673 zero_cod, sizeof(zero_cod), NULL);
3674
3675new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003676 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003677
3678 if (match.sk)
3679 sock_put(match.sk);
3680
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003681 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003682}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003683
Johan Hedberg96570ff2013-05-29 09:51:29 +03003684int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3685{
3686 struct pending_cmd *cmd;
3687 u8 status;
3688
3689 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3690 if (!cmd)
3691 return -ENOENT;
3692
3693 if (err == -ERFKILL)
3694 status = MGMT_STATUS_RFKILLED;
3695 else
3696 status = MGMT_STATUS_FAILED;
3697
3698 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3699
3700 mgmt_pending_remove(cmd);
3701
3702 return err;
3703}
3704
Johan Hedberg744cf192011-11-08 20:40:14 +02003705int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003706{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003707 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003708 bool changed = false;
3709 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003710
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003711 if (discoverable) {
3712 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3713 changed = true;
3714 } else {
3715 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3716 changed = true;
3717 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003718
Johan Hedberged9b5f22012-02-21 20:47:06 +02003719 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003720 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003721
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003722 if (changed)
3723 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003724
Johan Hedberg73f22f62010-12-29 16:00:25 +02003725 if (match.sk)
3726 sock_put(match.sk);
3727
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003728 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003729}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003730
Johan Hedberg744cf192011-11-08 20:40:14 +02003731int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003732{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003733 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003734 bool changed = false;
3735 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003736
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003737 if (connectable) {
3738 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3739 changed = true;
3740 } else {
3741 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3742 changed = true;
3743 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003744
Johan Hedberg2b76f452013-03-15 17:07:04 -05003745 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003746
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003747 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003748 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003749
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003750 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003751}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003752
Johan Hedberg744cf192011-11-08 20:40:14 +02003753int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003754{
Johan Hedbergca69b792011-11-11 18:10:00 +02003755 u8 mgmt_err = mgmt_status(status);
3756
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003757 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003758 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003759 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003760
3761 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003762 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003763 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003764
3765 return 0;
3766}
3767
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003768int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3769 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003770{
Johan Hedberg86742e12011-11-07 23:13:38 +02003771 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003772
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003773 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003774
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003775 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003776 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003777 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003778 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003779 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003780 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003781
Johan Hedberg744cf192011-11-08 20:40:14 +02003782 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003783}
Johan Hedbergf7520542011-01-20 12:34:39 +02003784
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003785int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3786{
3787 struct mgmt_ev_new_long_term_key ev;
3788
3789 memset(&ev, 0, sizeof(ev));
3790
3791 ev.store_hint = persistent;
3792 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003793 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003794 ev.key.authenticated = key->authenticated;
3795 ev.key.enc_size = key->enc_size;
3796 ev.key.ediv = key->ediv;
3797
3798 if (key->type == HCI_SMP_LTK)
3799 ev.key.master = 1;
3800
3801 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3802 memcpy(ev.key.val, key->val, sizeof(key->val));
3803
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003804 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3805 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003806}
3807
Johan Hedbergafc747a2012-01-15 18:11:07 +02003808int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003809 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3810 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003811{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003812 char buf[512];
3813 struct mgmt_ev_device_connected *ev = (void *) buf;
3814 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003815
Johan Hedbergb644ba32012-01-17 21:48:47 +02003816 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003817 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003818
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003819 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003820
Johan Hedbergb644ba32012-01-17 21:48:47 +02003821 if (name_len > 0)
3822 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003823 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003824
3825 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003826 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003827 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003828
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003829 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003830
3831 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003832 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003833}
3834
Johan Hedberg8962ee72011-01-20 12:40:27 +02003835static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3836{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003837 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003838 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003839 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003840
Johan Hedberg88c3df12012-02-09 14:27:38 +02003841 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3842 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003843
Johan Hedbergaee9b212012-02-18 15:07:59 +02003844 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003845 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003846
3847 *sk = cmd->sk;
3848 sock_hold(*sk);
3849
Johan Hedberga664b5b2011-02-19 12:06:02 -03003850 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003851}
3852
Johan Hedberg124f6e32012-02-09 13:50:12 +02003853static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003854{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003855 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003856 struct mgmt_cp_unpair_device *cp = cmd->param;
3857 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003858
3859 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003860 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3861 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003862
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003863 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3864
Johan Hedbergaee9b212012-02-18 15:07:59 +02003865 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003866
3867 mgmt_pending_remove(cmd);
3868}
3869
Johan Hedbergafc747a2012-01-15 18:11:07 +02003870int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003871 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003872{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003873 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003874 struct sock *sk = NULL;
3875 int err;
3876
Johan Hedberg744cf192011-11-08 20:40:14 +02003877 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003878
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003879 bacpy(&ev.addr.bdaddr, bdaddr);
3880 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3881 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003882
Johan Hedbergafc747a2012-01-15 18:11:07 +02003883 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003884 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003885
3886 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003887 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003888
Johan Hedberg124f6e32012-02-09 13:50:12 +02003889 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003890 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003891
Johan Hedberg8962ee72011-01-20 12:40:27 +02003892 return err;
3893}
3894
Johan Hedberg88c3df12012-02-09 14:27:38 +02003895int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003896 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003897{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003898 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003899 struct pending_cmd *cmd;
3900 int err;
3901
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003902 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3903 hdev);
3904
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003905 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003906 if (!cmd)
3907 return -ENOENT;
3908
Johan Hedberg88c3df12012-02-09 14:27:38 +02003909 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003910 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003911
Johan Hedberg88c3df12012-02-09 14:27:38 +02003912 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003913 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003914
Johan Hedberga664b5b2011-02-19 12:06:02 -03003915 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003916
3917 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003918}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003919
Johan Hedberg48264f02011-11-09 13:58:58 +02003920int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003921 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003922{
3923 struct mgmt_ev_connect_failed ev;
3924
Johan Hedberg4c659c32011-11-07 23:13:39 +02003925 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003926 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003927 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003928
Johan Hedberg744cf192011-11-08 20:40:14 +02003929 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003930}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003931
Johan Hedberg744cf192011-11-08 20:40:14 +02003932int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003933{
3934 struct mgmt_ev_pin_code_request ev;
3935
Johan Hedbergd8457692012-02-17 14:24:57 +02003936 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003937 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003938 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003939
Johan Hedberg744cf192011-11-08 20:40:14 +02003940 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003941 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003942}
3943
Johan Hedberg744cf192011-11-08 20:40:14 +02003944int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003945 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003946{
3947 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003948 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003949 int err;
3950
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003951 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003952 if (!cmd)
3953 return -ENOENT;
3954
Johan Hedbergd8457692012-02-17 14:24:57 +02003955 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003956 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003957
Johan Hedbergaee9b212012-02-18 15:07:59 +02003958 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003959 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003960
Johan Hedberga664b5b2011-02-19 12:06:02 -03003961 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003962
3963 return err;
3964}
3965
Johan Hedberg744cf192011-11-08 20:40:14 +02003966int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003967 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003968{
3969 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003970 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003971 int err;
3972
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003973 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003974 if (!cmd)
3975 return -ENOENT;
3976
Johan Hedbergd8457692012-02-17 14:24:57 +02003977 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003978 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003979
Johan Hedbergaee9b212012-02-18 15:07:59 +02003980 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003981 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003982
Johan Hedberga664b5b2011-02-19 12:06:02 -03003983 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003984
3985 return err;
3986}
Johan Hedberga5c29682011-02-19 12:05:57 -03003987
Johan Hedberg744cf192011-11-08 20:40:14 +02003988int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003989 u8 link_type, u8 addr_type, __le32 value,
3990 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003991{
3992 struct mgmt_ev_user_confirm_request ev;
3993
Johan Hedberg744cf192011-11-08 20:40:14 +02003994 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003995
Johan Hedberg272d90d2012-02-09 15:26:12 +02003996 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003997 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003998 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003999 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004000
Johan Hedberg744cf192011-11-08 20:40:14 +02004001 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004002 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004003}
4004
Johan Hedberg272d90d2012-02-09 15:26:12 +02004005int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004006 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004007{
4008 struct mgmt_ev_user_passkey_request ev;
4009
4010 BT_DBG("%s", hdev->name);
4011
Johan Hedberg272d90d2012-02-09 15:26:12 +02004012 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004013 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004014
4015 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004016 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004017}
4018
Brian Gix0df4c182011-11-16 13:53:13 -08004019static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004020 u8 link_type, u8 addr_type, u8 status,
4021 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004022{
4023 struct pending_cmd *cmd;
4024 struct mgmt_rp_user_confirm_reply rp;
4025 int err;
4026
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004027 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004028 if (!cmd)
4029 return -ENOENT;
4030
Johan Hedberg272d90d2012-02-09 15:26:12 +02004031 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004032 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004033 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004034 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004035
Johan Hedberga664b5b2011-02-19 12:06:02 -03004036 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004037
4038 return err;
4039}
4040
Johan Hedberg744cf192011-11-08 20:40:14 +02004041int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004042 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004043{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004044 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004045 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004046}
4047
Johan Hedberg272d90d2012-02-09 15:26:12 +02004048int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004049 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004050{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004051 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004052 status,
4053 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004054}
Johan Hedberg2a611692011-02-19 12:06:00 -03004055
Brian Gix604086b2011-11-23 08:28:33 -08004056int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004057 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004058{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004059 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004060 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004061}
4062
Johan Hedberg272d90d2012-02-09 15:26:12 +02004063int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004064 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004065{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004066 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004067 status,
4068 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004069}
4070
Johan Hedberg92a25252012-09-06 18:39:26 +03004071int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4072 u8 link_type, u8 addr_type, u32 passkey,
4073 u8 entered)
4074{
4075 struct mgmt_ev_passkey_notify ev;
4076
4077 BT_DBG("%s", hdev->name);
4078
4079 bacpy(&ev.addr.bdaddr, bdaddr);
4080 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4081 ev.passkey = __cpu_to_le32(passkey);
4082 ev.entered = entered;
4083
4084 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4085}
4086
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004087int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004088 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004089{
4090 struct mgmt_ev_auth_failed ev;
4091
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004092 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004093 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004094 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004095
Johan Hedberg744cf192011-11-08 20:40:14 +02004096 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004097}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004098
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004099int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4100{
4101 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004102 bool changed = false;
4103 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004104
4105 if (status) {
4106 u8 mgmt_err = mgmt_status(status);
4107 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004108 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004109 return 0;
4110 }
4111
Johan Hedberg47990ea2012-02-22 11:58:37 +02004112 if (test_bit(HCI_AUTH, &hdev->flags)) {
4113 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4114 changed = true;
4115 } else {
4116 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4117 changed = true;
4118 }
4119
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004120 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004121 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004122
Johan Hedberg47990ea2012-02-22 11:58:37 +02004123 if (changed)
4124 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004125
4126 if (match.sk)
4127 sock_put(match.sk);
4128
4129 return err;
4130}
4131
Johan Hedberg890ea892013-03-15 17:06:52 -05004132static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004133{
Johan Hedberg890ea892013-03-15 17:06:52 -05004134 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004135 struct hci_cp_write_eir cp;
4136
Johan Hedberg976eb202012-10-24 21:12:01 +03004137 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004138 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004139
Johan Hedbergc80da272012-02-22 15:38:48 +02004140 memset(hdev->eir, 0, sizeof(hdev->eir));
4141
Johan Hedbergcacaf522012-02-21 00:52:42 +02004142 memset(&cp, 0, sizeof(cp));
4143
Johan Hedberg890ea892013-03-15 17:06:52 -05004144 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004145}
4146
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004147int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004148{
4149 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004150 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004151 bool changed = false;
4152 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004153
4154 if (status) {
4155 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004156
4157 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004158 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004159 err = new_settings(hdev, NULL);
4160
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004161 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4162 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004163
4164 return err;
4165 }
4166
4167 if (enable) {
4168 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4169 changed = true;
4170 } else {
4171 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4172 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004173 }
4174
4175 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4176
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004177 if (changed)
4178 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004179
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004180 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004181 sock_put(match.sk);
4182
Johan Hedberg890ea892013-03-15 17:06:52 -05004183 hci_req_init(&req, hdev);
4184
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004185 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004186 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004187 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004188 clear_eir(&req);
4189
4190 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004191
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004192 return err;
4193}
4194
Johan Hedberg92da6092013-03-15 17:06:55 -05004195static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004196{
4197 struct cmd_lookup *match = data;
4198
Johan Hedberg90e70452012-02-23 23:09:40 +02004199 if (match->sk == NULL) {
4200 match->sk = cmd->sk;
4201 sock_hold(match->sk);
4202 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004203}
4204
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004205int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004206 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004207{
Johan Hedberg90e70452012-02-23 23:09:40 +02004208 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4209 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004210
Johan Hedberg92da6092013-03-15 17:06:55 -05004211 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4212 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4213 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004214
4215 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004216 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4217 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004218
4219 if (match.sk)
4220 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004221
4222 return err;
4223}
4224
Johan Hedberg744cf192011-11-08 20:40:14 +02004225int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004226{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004227 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004228 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004229
Johan Hedberg13928972013-03-15 17:07:00 -05004230 if (status)
4231 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004232
4233 memset(&ev, 0, sizeof(ev));
4234 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004235 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004236
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004237 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004238 if (!cmd) {
4239 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004240
Johan Hedberg13928972013-03-15 17:07:00 -05004241 /* If this is a HCI command related to powering on the
4242 * HCI dev don't send any mgmt signals.
4243 */
4244 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4245 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004246 }
4247
Johan Hedberg13928972013-03-15 17:07:00 -05004248 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4249 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004250}
Szymon Jancc35938b2011-03-22 13:12:21 +01004251
Johan Hedberg744cf192011-11-08 20:40:14 +02004252int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004253 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004254{
4255 struct pending_cmd *cmd;
4256 int err;
4257
Johan Hedberg744cf192011-11-08 20:40:14 +02004258 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004259
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004260 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004261 if (!cmd)
4262 return -ENOENT;
4263
4264 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004265 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4266 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004267 } else {
4268 struct mgmt_rp_read_local_oob_data rp;
4269
4270 memcpy(rp.hash, hash, sizeof(rp.hash));
4271 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4272
Johan Hedberg744cf192011-11-08 20:40:14 +02004273 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004274 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4275 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004276 }
4277
4278 mgmt_pending_remove(cmd);
4279
4280 return err;
4281}
Johan Hedberge17acd42011-03-30 23:57:16 +03004282
Johan Hedberg48264f02011-11-09 13:58:58 +02004283int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004284 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4285 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004286{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004287 char buf[512];
4288 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004289 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004290
Andre Guedes12602d02013-04-30 15:29:40 -03004291 if (!hci_discovery_active(hdev))
4292 return -EPERM;
4293
Johan Hedberg1dc06092012-01-15 21:01:23 +02004294 /* Leave 5 bytes for a potential CoD field */
4295 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004296 return -EINVAL;
4297
Johan Hedberg1dc06092012-01-15 21:01:23 +02004298 memset(buf, 0, sizeof(buf));
4299
Johan Hedberge319d2e2012-01-15 19:51:59 +02004300 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004301 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004302 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004303 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304304 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004305 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304306 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004307
Johan Hedberg1dc06092012-01-15 21:01:23 +02004308 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004309 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004310
Johan Hedberg1dc06092012-01-15 21:01:23 +02004311 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4312 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004313 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004314
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004315 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004316 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004317
Johan Hedberge319d2e2012-01-15 19:51:59 +02004318 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004319}
Johan Hedberga88a9652011-03-30 13:18:12 +03004320
Johan Hedbergb644ba32012-01-17 21:48:47 +02004321int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004322 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004323{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004324 struct mgmt_ev_device_found *ev;
4325 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4326 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004327
Johan Hedbergb644ba32012-01-17 21:48:47 +02004328 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004329
Johan Hedbergb644ba32012-01-17 21:48:47 +02004330 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004331
Johan Hedbergb644ba32012-01-17 21:48:47 +02004332 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004333 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004334 ev->rssi = rssi;
4335
4336 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004337 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004338
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004339 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004340
Johan Hedberg053c7e02012-02-04 00:06:00 +02004341 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004342 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004343}
Johan Hedberg314b2382011-04-27 10:29:57 -04004344
Johan Hedberg744cf192011-11-08 20:40:14 +02004345int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004346{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004347 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004348 struct pending_cmd *cmd;
4349
Andre Guedes343fb142011-11-22 17:14:19 -03004350 BT_DBG("%s discovering %u", hdev->name, discovering);
4351
Johan Hedberg164a6e72011-11-01 17:06:44 +02004352 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004353 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004354 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004355 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004356
4357 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004358 u8 type = hdev->discovery.type;
4359
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004360 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4361 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004362 mgmt_pending_remove(cmd);
4363 }
4364
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004365 memset(&ev, 0, sizeof(ev));
4366 ev.type = hdev->discovery.type;
4367 ev.discovering = discovering;
4368
4369 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004370}
Antti Julku5e762442011-08-25 16:48:02 +03004371
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004372int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004373{
4374 struct pending_cmd *cmd;
4375 struct mgmt_ev_device_blocked ev;
4376
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004377 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004378
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004379 bacpy(&ev.addr.bdaddr, bdaddr);
4380 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004381
Johan Hedberg744cf192011-11-08 20:40:14 +02004382 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004383 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004384}
4385
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004386int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004387{
4388 struct pending_cmd *cmd;
4389 struct mgmt_ev_device_unblocked ev;
4390
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004391 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004392
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004393 bacpy(&ev.addr.bdaddr, bdaddr);
4394 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004395
Johan Hedberg744cf192011-11-08 20:40:14 +02004396 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004397 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004398}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01004399
4400module_param(enable_hs, bool, 0644);
4401MODULE_PARM_DESC(enable_hs, "Enable High Speed support");