blob: 461d5bb245a8fa5db1ecd679820fbf4146e3f080 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg2da9c552012-02-17 14:39:28 +020035#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060036#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020037
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070076 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030077 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030078 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070079 MGMT_OP_SET_STATIC_ADDRESS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020080};
81
82static const u16 mgmt_events[] = {
83 MGMT_EV_CONTROLLER_ERROR,
84 MGMT_EV_INDEX_ADDED,
85 MGMT_EV_INDEX_REMOVED,
86 MGMT_EV_NEW_SETTINGS,
87 MGMT_EV_CLASS_OF_DEV_CHANGED,
88 MGMT_EV_LOCAL_NAME_CHANGED,
89 MGMT_EV_NEW_LINK_KEY,
90 MGMT_EV_NEW_LONG_TERM_KEY,
91 MGMT_EV_DEVICE_CONNECTED,
92 MGMT_EV_DEVICE_DISCONNECTED,
93 MGMT_EV_CONNECT_FAILED,
94 MGMT_EV_PIN_CODE_REQUEST,
95 MGMT_EV_USER_CONFIRM_REQUEST,
96 MGMT_EV_USER_PASSKEY_REQUEST,
97 MGMT_EV_AUTH_FAILED,
98 MGMT_EV_DEVICE_FOUND,
99 MGMT_EV_DISCOVERING,
100 MGMT_EV_DEVICE_BLOCKED,
101 MGMT_EV_DEVICE_UNBLOCKED,
102 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300103 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200104};
105
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800106#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200107
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200108#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
109 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
110
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200111struct pending_cmd {
112 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200113 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100115 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300117 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118};
119
Johan Hedbergca69b792011-11-11 18:10:00 +0200120/* HCI to MGMT error code conversion table */
121static u8 mgmt_status_table[] = {
122 MGMT_STATUS_SUCCESS,
123 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
124 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
125 MGMT_STATUS_FAILED, /* Hardware Failure */
126 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
127 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
128 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
129 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
130 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
132 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
133 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
134 MGMT_STATUS_BUSY, /* Command Disallowed */
135 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
136 MGMT_STATUS_REJECTED, /* Rejected Security */
137 MGMT_STATUS_REJECTED, /* Rejected Personal */
138 MGMT_STATUS_TIMEOUT, /* Host Timeout */
139 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
140 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
141 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
142 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
143 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
144 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
145 MGMT_STATUS_BUSY, /* Repeated Attempts */
146 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
147 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
148 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
149 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
150 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
151 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
153 MGMT_STATUS_FAILED, /* Unspecified Error */
154 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
155 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
156 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
157 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
158 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
159 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
160 MGMT_STATUS_FAILED, /* Unit Link Key Used */
161 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
162 MGMT_STATUS_TIMEOUT, /* Instant Passed */
163 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
164 MGMT_STATUS_FAILED, /* Transaction Collision */
165 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
166 MGMT_STATUS_REJECTED, /* QoS Rejected */
167 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
168 MGMT_STATUS_REJECTED, /* Insufficient Security */
169 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
170 MGMT_STATUS_BUSY, /* Role Switch Pending */
171 MGMT_STATUS_FAILED, /* Slot Violation */
172 MGMT_STATUS_FAILED, /* Role Switch Failed */
173 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
174 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
175 MGMT_STATUS_BUSY, /* Host Busy Pairing */
176 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
177 MGMT_STATUS_BUSY, /* Controller Busy */
178 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
179 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
180 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
181 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
182 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
183};
184
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300185bool mgmt_valid_hdev(struct hci_dev *hdev)
186{
187 return hdev->dev_type == HCI_BREDR;
188}
189
Johan Hedbergca69b792011-11-11 18:10:00 +0200190static u8 mgmt_status(u8 hci_status)
191{
192 if (hci_status < ARRAY_SIZE(mgmt_status_table))
193 return mgmt_status_table[hci_status];
194
195 return MGMT_STATUS_FAILED;
196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan 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;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700384 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100385
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300386 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200387 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300388 settings |= MGMT_SETTING_ADVERTISING;
389 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500404 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
405 settings |= MGMT_SETTING_FAST_CONNECTABLE;
406
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200407 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_DISCOVERABLE;
409
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200410 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_PAIRABLE;
412
Johan Hedberg56f87902013-10-02 13:43:13 +0300413 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_BREDR;
415
Johan Hedberg06199cf2012-02-22 16:37:11 +0200416 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg47990ea2012-02-22 11:58:37 +0200419 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200421
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200422 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200424
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200425 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
426 settings |= MGMT_SETTING_HS;
427
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300428 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
429 settings |= MGMT_SETTING_ADVERTISING;
430
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200431 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200432}
433
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300434#define PNP_INFO_SVCLASS_ID 0x1200
435
Johan Hedberg213202e2013-01-27 00:31:33 +0200436static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
437{
438 u8 *ptr = data, *uuids_start = NULL;
439 struct bt_uuid *uuid;
440
441 if (len < 4)
442 return ptr;
443
444 list_for_each_entry(uuid, &hdev->uuids, list) {
445 u16 uuid16;
446
447 if (uuid->size != 16)
448 continue;
449
450 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
451 if (uuid16 < 0x1100)
452 continue;
453
454 if (uuid16 == PNP_INFO_SVCLASS_ID)
455 continue;
456
457 if (!uuids_start) {
458 uuids_start = ptr;
459 uuids_start[0] = 1;
460 uuids_start[1] = EIR_UUID16_ALL;
461 ptr += 2;
462 }
463
464 /* Stop if not enough space to put next UUID */
465 if ((ptr - data) + sizeof(u16) > len) {
466 uuids_start[1] = EIR_UUID16_SOME;
467 break;
468 }
469
470 *ptr++ = (uuid16 & 0x00ff);
471 *ptr++ = (uuid16 & 0xff00) >> 8;
472 uuids_start[0] += sizeof(uuid16);
473 }
474
475 return ptr;
476}
477
Johan Hedbergcdf19632013-01-27 00:31:34 +0200478static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
479{
480 u8 *ptr = data, *uuids_start = NULL;
481 struct bt_uuid *uuid;
482
483 if (len < 6)
484 return ptr;
485
486 list_for_each_entry(uuid, &hdev->uuids, list) {
487 if (uuid->size != 32)
488 continue;
489
490 if (!uuids_start) {
491 uuids_start = ptr;
492 uuids_start[0] = 1;
493 uuids_start[1] = EIR_UUID32_ALL;
494 ptr += 2;
495 }
496
497 /* Stop if not enough space to put next UUID */
498 if ((ptr - data) + sizeof(u32) > len) {
499 uuids_start[1] = EIR_UUID32_SOME;
500 break;
501 }
502
503 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
504 ptr += sizeof(u32);
505 uuids_start[0] += sizeof(u32);
506 }
507
508 return ptr;
509}
510
Johan Hedbergc00d5752013-01-27 00:31:35 +0200511static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
512{
513 u8 *ptr = data, *uuids_start = NULL;
514 struct bt_uuid *uuid;
515
516 if (len < 18)
517 return ptr;
518
519 list_for_each_entry(uuid, &hdev->uuids, list) {
520 if (uuid->size != 128)
521 continue;
522
523 if (!uuids_start) {
524 uuids_start = ptr;
525 uuids_start[0] = 1;
526 uuids_start[1] = EIR_UUID128_ALL;
527 ptr += 2;
528 }
529
530 /* Stop if not enough space to put next UUID */
531 if ((ptr - data) + 16 > len) {
532 uuids_start[1] = EIR_UUID128_SOME;
533 break;
534 }
535
536 memcpy(ptr, uuid->uuid, 16);
537 ptr += 16;
538 uuids_start[0] += 16;
539 }
540
541 return ptr;
542}
543
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300544static void create_eir(struct hci_dev *hdev, u8 *data)
545{
546 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547 size_t name_len;
548
549 name_len = strlen(hdev->dev_name);
550
551 if (name_len > 0) {
552 /* EIR Data type */
553 if (name_len > 48) {
554 name_len = 48;
555 ptr[1] = EIR_NAME_SHORT;
556 } else
557 ptr[1] = EIR_NAME_COMPLETE;
558
559 /* EIR Data length */
560 ptr[0] = name_len + 1;
561
562 memcpy(ptr + 2, hdev->dev_name, name_len);
563
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 ptr += (name_len + 2);
565 }
566
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100567 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700568 ptr[0] = 2;
569 ptr[1] = EIR_TX_POWER;
570 ptr[2] = (u8) hdev->inq_tx_power;
571
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700572 ptr += 3;
573 }
574
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700575 if (hdev->devid_source > 0) {
576 ptr[0] = 9;
577 ptr[1] = EIR_DEVICE_ID;
578
579 put_unaligned_le16(hdev->devid_source, ptr + 2);
580 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
581 put_unaligned_le16(hdev->devid_product, ptr + 6);
582 put_unaligned_le16(hdev->devid_version, ptr + 8);
583
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700584 ptr += 10;
585 }
586
Johan Hedberg213202e2013-01-27 00:31:33 +0200587 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200588 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200589 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300590}
591
Johan Hedberg890ea892013-03-15 17:06:52 -0500592static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300593{
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595 struct hci_cp_write_eir cp;
596
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200597 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500598 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200599
Johan Hedberg976eb202012-10-24 21:12:01 +0300600 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500601 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300602
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200603 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500604 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300605
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200606 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500607 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608
609 memset(&cp, 0, sizeof(cp));
610
611 create_eir(hdev, cp.data);
612
613 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500614 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300615
616 memcpy(hdev->eir, cp.data, sizeof(cp.data));
617
Johan Hedberg890ea892013-03-15 17:06:52 -0500618 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300619}
620
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621static u8 get_service_classes(struct hci_dev *hdev)
622{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300623 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624 u8 val = 0;
625
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300626 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628
629 return val;
630}
631
Johan Hedberg890ea892013-03-15 17:06:52 -0500632static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200633{
Johan Hedberg890ea892013-03-15 17:06:52 -0500634 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200635 u8 cod[3];
636
637 BT_DBG("%s", hdev->name);
638
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200639 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500640 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200641
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200642 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500643 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200644
645 cod[0] = hdev->minor_class;
646 cod[1] = hdev->major_class;
647 cod[2] = get_service_classes(hdev);
648
649 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500650 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200651
Johan Hedberg890ea892013-03-15 17:06:52 -0500652 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200653}
654
Johan Hedberg7d785252011-12-15 00:47:39 +0200655static void service_cache_off(struct work_struct *work)
656{
657 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300658 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500659 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200660
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200661 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200662 return;
663
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 hci_req_init(&req, hdev);
665
Johan Hedberg7d785252011-12-15 00:47:39 +0200666 hci_dev_lock(hdev);
667
Johan Hedberg890ea892013-03-15 17:06:52 -0500668 update_eir(&req);
669 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200670
671 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500672
673 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200674}
675
Johan Hedberg6a919082012-02-28 06:17:26 +0200676static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200677{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200678 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200679 return;
680
Johan Hedberg4f87da82012-03-02 19:55:56 +0200681 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200682
Johan Hedberg4f87da82012-03-02 19:55:56 +0200683 /* Non-mgmt controlled devices get this bit set
684 * implicitly so that pairing works for them, however
685 * for mgmt we require user-space to explicitly enable
686 * it
687 */
688 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200689}
690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200691static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200693{
694 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200696 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200697
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300698 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200699
Johan Hedberg03811012010-12-08 00:21:06 +0200700 memset(&rp, 0, sizeof(rp));
701
Johan Hedberg03811012010-12-08 00:21:06 +0200702 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200703
704 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200705 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200706
707 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
708 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
709
710 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200711
712 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200713 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300715 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200716
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200717 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300718 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200719}
720
721static void mgmt_pending_free(struct pending_cmd *cmd)
722{
723 sock_put(cmd->sk);
724 kfree(cmd->param);
725 kfree(cmd);
726}
727
728static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300729 struct hci_dev *hdev, void *data,
730 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200731{
732 struct pending_cmd *cmd;
733
Andre Guedes12b94562012-06-07 19:05:45 -0300734 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200735 if (!cmd)
736 return NULL;
737
738 cmd->opcode = opcode;
739 cmd->index = hdev->id;
740
Andre Guedes12b94562012-06-07 19:05:45 -0300741 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 if (!cmd->param) {
743 kfree(cmd);
744 return NULL;
745 }
746
747 if (data)
748 memcpy(cmd->param, data, len);
749
750 cmd->sk = sk;
751 sock_hold(sk);
752
753 list_add(&cmd->list, &hdev->mgmt_pending);
754
755 return cmd;
756}
757
758static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300759 void (*cb)(struct pending_cmd *cmd,
760 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300761 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200762{
Andre Guedesa3d09352013-02-01 11:21:30 -0300763 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Andre Guedesa3d09352013-02-01 11:21:30 -0300765 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200766 if (opcode > 0 && cmd->opcode != opcode)
767 continue;
768
769 cb(cmd, data);
770 }
771}
772
773static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
774{
775 struct pending_cmd *cmd;
776
777 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
778 if (cmd->opcode == opcode)
779 return cmd;
780 }
781
782 return NULL;
783}
784
785static void mgmt_pending_remove(struct pending_cmd *cmd)
786{
787 list_del(&cmd->list);
788 mgmt_pending_free(cmd);
789}
790
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200792{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200793 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200794
Johan Hedbergaee9b212012-02-18 15:07:59 +0200795 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200797}
798
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200799static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300800 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200801{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300802 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200803 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200804 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200806 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedberga7e80f22013-01-09 16:05:19 +0200808 if (cp->val != 0x00 && cp->val != 0x01)
809 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
810 MGMT_STATUS_INVALID_PARAMS);
811
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300812 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200813
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300814 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
815 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
816 MGMT_STATUS_BUSY);
817 goto failed;
818 }
819
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100820 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
821 cancel_delayed_work(&hdev->power_off);
822
823 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200824 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
825 data, len);
826 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100827 goto failed;
828 }
829 }
830
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200831 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200832 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200833 goto failed;
834 }
835
Johan Hedberg03811012010-12-08 00:21:06 +0200836 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
837 if (!cmd) {
838 err = -ENOMEM;
839 goto failed;
840 }
841
842 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200843 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200844 else
Johan Hedberg19202572013-01-14 22:33:51 +0200845 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200846
847 err = 0;
848
849failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300850 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200851 return err;
852}
853
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300854static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
855 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200856{
857 struct sk_buff *skb;
858 struct mgmt_hdr *hdr;
859
Andre Guedes790eff42012-06-07 19:05:46 -0300860 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200861 if (!skb)
862 return -ENOMEM;
863
864 hdr = (void *) skb_put(skb, sizeof(*hdr));
865 hdr->opcode = cpu_to_le16(event);
866 if (hdev)
867 hdr->index = cpu_to_le16(hdev->id);
868 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530869 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200870 hdr->len = cpu_to_le16(data_len);
871
872 if (data)
873 memcpy(skb_put(skb, data_len), data, data_len);
874
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100875 /* Time stamp */
876 __net_timestamp(skb);
877
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200878 hci_send_to_control(skb, skip_sk);
879 kfree_skb(skb);
880
881 return 0;
882}
883
884static int new_settings(struct hci_dev *hdev, struct sock *skip)
885{
886 __le32 ev;
887
888 ev = cpu_to_le32(get_current_settings(hdev));
889
890 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
891}
892
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300893struct cmd_lookup {
894 struct sock *sk;
895 struct hci_dev *hdev;
896 u8 mgmt_status;
897};
898
899static void settings_rsp(struct pending_cmd *cmd, void *data)
900{
901 struct cmd_lookup *match = data;
902
903 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
904
905 list_del(&cmd->list);
906
907 if (match->sk == NULL) {
908 match->sk = cmd->sk;
909 sock_hold(match->sk);
910 }
911
912 mgmt_pending_free(cmd);
913}
914
915static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
916{
917 u8 *status = data;
918
919 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
920 mgmt_pending_remove(cmd);
921}
922
Johan Hedberge6fe7982013-10-02 15:45:22 +0300923static u8 mgmt_bredr_support(struct hci_dev *hdev)
924{
925 if (!lmp_bredr_capable(hdev))
926 return MGMT_STATUS_NOT_SUPPORTED;
927 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
928 return MGMT_STATUS_REJECTED;
929 else
930 return MGMT_STATUS_SUCCESS;
931}
932
933static u8 mgmt_le_support(struct hci_dev *hdev)
934{
935 if (!lmp_le_capable(hdev))
936 return MGMT_STATUS_NOT_SUPPORTED;
937 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
938 return MGMT_STATUS_REJECTED;
939 else
940 return MGMT_STATUS_SUCCESS;
941}
942
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200943static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300944 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200945{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300946 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200947 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200948 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300949 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200950 int err;
951
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200952 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200953
Johan Hedberge6fe7982013-10-02 15:45:22 +0300954 status = mgmt_bredr_support(hdev);
955 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300956 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300957 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300958
Johan Hedberga7e80f22013-01-09 16:05:19 +0200959 if (cp->val != 0x00 && cp->val != 0x01)
960 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
961 MGMT_STATUS_INVALID_PARAMS);
962
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700963 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100964 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200965 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300966 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200967
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300968 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200969
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200971 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300972 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200973 goto failed;
974 }
975
976 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300977 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200978 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300979 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200980 goto failed;
981 }
982
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200983 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200984 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300985 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200986 goto failed;
987 }
988
989 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200990 bool changed = false;
991
992 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
993 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
994 changed = true;
995 }
996
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200997 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200998 if (err < 0)
999 goto failed;
1000
1001 if (changed)
1002 err = new_settings(hdev, sk);
1003
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001004 goto failed;
1005 }
1006
1007 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001008 if (hdev->discov_timeout > 0) {
1009 cancel_delayed_work(&hdev->discov_off);
1010 hdev->discov_timeout = 0;
1011 }
1012
1013 if (cp->val && timeout > 0) {
1014 hdev->discov_timeout = timeout;
1015 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1016 msecs_to_jiffies(hdev->discov_timeout * 1000));
1017 }
1018
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001019 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001020 goto failed;
1021 }
1022
1023 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1024 if (!cmd) {
1025 err = -ENOMEM;
1026 goto failed;
1027 }
1028
1029 scan = SCAN_PAGE;
1030
1031 if (cp->val)
1032 scan |= SCAN_INQUIRY;
1033 else
1034 cancel_delayed_work(&hdev->discov_off);
1035
1036 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1037 if (err < 0)
1038 mgmt_pending_remove(cmd);
1039
Johan Hedberg03811012010-12-08 00:21:06 +02001040 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001041 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001042
1043failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001044 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001045 return err;
1046}
1047
Johan Hedberg406d7802013-03-15 17:07:09 -05001048static void write_fast_connectable(struct hci_request *req, bool enable)
1049{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001050 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001051 struct hci_cp_write_page_scan_activity acp;
1052 u8 type;
1053
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001054 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1055 return;
1056
Johan Hedberg406d7802013-03-15 17:07:09 -05001057 if (enable) {
1058 type = PAGE_SCAN_TYPE_INTERLACED;
1059
1060 /* 160 msec page scan interval */
1061 acp.interval = __constant_cpu_to_le16(0x0100);
1062 } else {
1063 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1064
1065 /* default 1.28 sec page scan */
1066 acp.interval = __constant_cpu_to_le16(0x0800);
1067 }
1068
1069 acp.window = __constant_cpu_to_le16(0x0012);
1070
Johan Hedbergbd98b992013-03-15 17:07:13 -05001071 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1072 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1073 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1074 sizeof(acp), &acp);
1075
1076 if (hdev->page_scan_type != type)
1077 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001078}
1079
Johan Hedberg2b76f452013-03-15 17:07:04 -05001080static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1081{
1082 struct pending_cmd *cmd;
1083
1084 BT_DBG("status 0x%02x", status);
1085
1086 hci_dev_lock(hdev);
1087
1088 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1089 if (!cmd)
1090 goto unlock;
1091
1092 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1093
1094 mgmt_pending_remove(cmd);
1095
1096unlock:
1097 hci_dev_unlock(hdev);
1098}
1099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001100static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001101 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001102{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001103 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001104 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001105 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001106 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001107 int err;
1108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001110
Johan Hedberge6fe7982013-10-02 15:45:22 +03001111 status = mgmt_bredr_support(hdev);
1112 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001113 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001114 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001115
Johan Hedberga7e80f22013-01-09 16:05:19 +02001116 if (cp->val != 0x00 && cp->val != 0x01)
1117 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1118 MGMT_STATUS_INVALID_PARAMS);
1119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001120 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001121
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001122 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001123 bool changed = false;
1124
1125 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1126 changed = true;
1127
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001128 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001129 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001130 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001131 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1132 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1133 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001134
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001135 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001136 if (err < 0)
1137 goto failed;
1138
1139 if (changed)
1140 err = new_settings(hdev, sk);
1141
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001142 goto failed;
1143 }
1144
1145 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001146 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001149 goto failed;
1150 }
1151
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001152 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001153 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001154 goto failed;
1155 }
1156
1157 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1158 if (!cmd) {
1159 err = -ENOMEM;
1160 goto failed;
1161 }
1162
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001163 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001165 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166 scan = 0;
1167
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001168 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001169 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001170 cancel_delayed_work(&hdev->discov_off);
1171 }
1172
Johan Hedberg2b76f452013-03-15 17:07:04 -05001173 hci_req_init(&req, hdev);
1174
1175 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1176
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001177 /* If we're going from non-connectable to connectable or
1178 * vice-versa when fast connectable is enabled ensure that fast
1179 * connectable gets disabled. write_fast_connectable won't do
1180 * anything if the page scan parameters are already what they
1181 * should be.
1182 */
1183 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001184 write_fast_connectable(&req, false);
1185
Johan Hedberg2b76f452013-03-15 17:07:04 -05001186 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187 if (err < 0)
1188 mgmt_pending_remove(cmd);
1189
1190failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001191 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192 return err;
1193}
1194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001196 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001197{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001198 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001199 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001201 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202
Johan Hedberga7e80f22013-01-09 16:05:19 +02001203 if (cp->val != 0x00 && cp->val != 0x01)
1204 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1205 MGMT_STATUS_INVALID_PARAMS);
1206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001207 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001208
1209 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001210 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001212 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001214 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001215 if (err < 0)
1216 goto failed;
1217
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001218 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001219
1220failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001221 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001222 return err;
1223}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001224
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001225static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1226 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001227{
1228 struct mgmt_mode *cp = data;
1229 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001230 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001231 int err;
1232
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001233 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001234
Johan Hedberge6fe7982013-10-02 15:45:22 +03001235 status = mgmt_bredr_support(hdev);
1236 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001237 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001238 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001239
Johan Hedberga7e80f22013-01-09 16:05:19 +02001240 if (cp->val != 0x00 && cp->val != 0x01)
1241 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1242 MGMT_STATUS_INVALID_PARAMS);
1243
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001244 hci_dev_lock(hdev);
1245
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001246 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001247 bool changed = false;
1248
1249 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001250 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001251 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1252 changed = true;
1253 }
1254
1255 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1256 if (err < 0)
1257 goto failed;
1258
1259 if (changed)
1260 err = new_settings(hdev, sk);
1261
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001262 goto failed;
1263 }
1264
1265 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001266 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001267 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001268 goto failed;
1269 }
1270
1271 val = !!cp->val;
1272
1273 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1274 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1275 goto failed;
1276 }
1277
1278 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1279 if (!cmd) {
1280 err = -ENOMEM;
1281 goto failed;
1282 }
1283
1284 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1285 if (err < 0) {
1286 mgmt_pending_remove(cmd);
1287 goto failed;
1288 }
1289
1290failed:
1291 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001292 return err;
1293}
1294
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001295static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001296{
1297 struct mgmt_mode *cp = data;
1298 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001299 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001300 int err;
1301
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001302 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001303
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001304 if (!lmp_ssp_capable(hdev))
1305 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1306 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001307
Johan Hedberga7e80f22013-01-09 16:05:19 +02001308 if (cp->val != 0x00 && cp->val != 0x01)
1309 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1310 MGMT_STATUS_INVALID_PARAMS);
1311
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001312 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001313
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001314 val = !!cp->val;
1315
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001316 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001317 bool changed = false;
1318
1319 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1320 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1321 changed = true;
1322 }
1323
1324 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1325 if (err < 0)
1326 goto failed;
1327
1328 if (changed)
1329 err = new_settings(hdev, sk);
1330
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001331 goto failed;
1332 }
1333
1334 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001335 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1336 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001337 goto failed;
1338 }
1339
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001340 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1341 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1342 goto failed;
1343 }
1344
1345 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1346 if (!cmd) {
1347 err = -ENOMEM;
1348 goto failed;
1349 }
1350
1351 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1352 if (err < 0) {
1353 mgmt_pending_remove(cmd);
1354 goto failed;
1355 }
1356
1357failed:
1358 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001359 return err;
1360}
1361
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001362static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001363{
1364 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001365 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001366 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001367 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001368
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001369 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001370
Johan Hedberge6fe7982013-10-02 15:45:22 +03001371 status = mgmt_bredr_support(hdev);
1372 if (status)
1373 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001374
Johan Hedberga7e80f22013-01-09 16:05:19 +02001375 if (cp->val != 0x00 && cp->val != 0x01)
1376 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1377 MGMT_STATUS_INVALID_PARAMS);
1378
Marcel Holtmannee392692013-10-01 22:59:23 -07001379 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001380
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001381 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001382 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001383 } else {
1384 if (hdev_is_powered(hdev)) {
1385 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1386 MGMT_STATUS_REJECTED);
1387 goto unlock;
1388 }
1389
Marcel Holtmannee392692013-10-01 22:59:23 -07001390 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001391 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001392
1393 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1394 if (err < 0)
1395 goto unlock;
1396
1397 if (changed)
1398 err = new_settings(hdev, sk);
1399
1400unlock:
1401 hci_dev_unlock(hdev);
1402 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001403}
1404
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001405static void le_enable_complete(struct hci_dev *hdev, u8 status)
1406{
1407 struct cmd_lookup match = { NULL, hdev };
1408
1409 if (status) {
1410 u8 mgmt_err = mgmt_status(status);
1411
1412 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1413 &mgmt_err);
1414 return;
1415 }
1416
1417 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1418
1419 new_settings(hdev, match.sk);
1420
1421 if (match.sk)
1422 sock_put(match.sk);
1423}
1424
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001425static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001426{
1427 struct mgmt_mode *cp = data;
1428 struct hci_cp_write_le_host_supported hci_cp;
1429 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001430 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001431 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001432 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001433
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001434 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001435
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001436 if (!lmp_le_capable(hdev))
1437 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1438 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001439
Johan Hedberga7e80f22013-01-09 16:05:19 +02001440 if (cp->val != 0x00 && cp->val != 0x01)
1441 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1442 MGMT_STATUS_INVALID_PARAMS);
1443
Johan Hedbergc73eee92013-04-19 18:35:21 +03001444 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001445 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001446 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1447 MGMT_STATUS_REJECTED);
1448
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001449 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001450
1451 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001452 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001453
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001454 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001455 bool changed = false;
1456
1457 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1458 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1459 changed = true;
1460 }
1461
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001462 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1463 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1464 changed = true;
1465 }
1466
Johan Hedberg06199cf2012-02-22 16:37:11 +02001467 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1468 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001469 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001470
1471 if (changed)
1472 err = new_settings(hdev, sk);
1473
Johan Hedberg1de028c2012-02-29 19:55:35 -08001474 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001475 }
1476
Johan Hedberg4375f102013-09-25 13:26:10 +03001477 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1478 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001479 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001480 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001481 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001482 }
1483
1484 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1485 if (!cmd) {
1486 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001487 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001488 }
1489
1490 memset(&hci_cp, 0, sizeof(hci_cp));
1491
1492 if (val) {
1493 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001494 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001495 }
1496
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001497 hci_req_init(&req, hdev);
1498
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001499 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1500 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1501
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001502 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1503 &hci_cp);
1504
1505 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301506 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001507 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001508
Johan Hedberg1de028c2012-02-29 19:55:35 -08001509unlock:
1510 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001511 return err;
1512}
1513
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001514/* This is a helper function to test for pending mgmt commands that can
1515 * cause CoD or EIR HCI commands. We can only allow one such pending
1516 * mgmt command at a time since otherwise we cannot easily track what
1517 * the current values are, will be, and based on that calculate if a new
1518 * HCI command needs to be sent and if yes with what value.
1519 */
1520static bool pending_eir_or_class(struct hci_dev *hdev)
1521{
1522 struct pending_cmd *cmd;
1523
1524 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1525 switch (cmd->opcode) {
1526 case MGMT_OP_ADD_UUID:
1527 case MGMT_OP_REMOVE_UUID:
1528 case MGMT_OP_SET_DEV_CLASS:
1529 case MGMT_OP_SET_POWERED:
1530 return true;
1531 }
1532 }
1533
1534 return false;
1535}
1536
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001537static const u8 bluetooth_base_uuid[] = {
1538 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1539 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1540};
1541
1542static u8 get_uuid_size(const u8 *uuid)
1543{
1544 u32 val;
1545
1546 if (memcmp(uuid, bluetooth_base_uuid, 12))
1547 return 128;
1548
1549 val = get_unaligned_le32(&uuid[12]);
1550 if (val > 0xffff)
1551 return 32;
1552
1553 return 16;
1554}
1555
Johan Hedberg92da6092013-03-15 17:06:55 -05001556static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1557{
1558 struct pending_cmd *cmd;
1559
1560 hci_dev_lock(hdev);
1561
1562 cmd = mgmt_pending_find(mgmt_op, hdev);
1563 if (!cmd)
1564 goto unlock;
1565
1566 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1567 hdev->dev_class, 3);
1568
1569 mgmt_pending_remove(cmd);
1570
1571unlock:
1572 hci_dev_unlock(hdev);
1573}
1574
1575static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1576{
1577 BT_DBG("status 0x%02x", status);
1578
1579 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1580}
1581
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001582static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001583{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001584 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001585 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001586 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001587 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001588 int err;
1589
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001591
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001592 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001593
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001594 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001595 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001596 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001597 goto failed;
1598 }
1599
Andre Guedes92c4c202012-06-07 19:05:44 -03001600 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001601 if (!uuid) {
1602 err = -ENOMEM;
1603 goto failed;
1604 }
1605
1606 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001607 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001608 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001609
Johan Hedbergde66aa62013-01-27 00:31:27 +02001610 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001611
Johan Hedberg890ea892013-03-15 17:06:52 -05001612 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001613
Johan Hedberg890ea892013-03-15 17:06:52 -05001614 update_class(&req);
1615 update_eir(&req);
1616
Johan Hedberg92da6092013-03-15 17:06:55 -05001617 err = hci_req_run(&req, add_uuid_complete);
1618 if (err < 0) {
1619 if (err != -ENODATA)
1620 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001621
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001622 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001623 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001624 goto failed;
1625 }
1626
1627 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001628 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001629 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001630 goto failed;
1631 }
1632
1633 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001634
1635failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001636 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001637 return err;
1638}
1639
Johan Hedberg24b78d02012-02-23 23:24:30 +02001640static bool enable_service_cache(struct hci_dev *hdev)
1641{
1642 if (!hdev_is_powered(hdev))
1643 return false;
1644
1645 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001646 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1647 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001648 return true;
1649 }
1650
1651 return false;
1652}
1653
Johan Hedberg92da6092013-03-15 17:06:55 -05001654static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1655{
1656 BT_DBG("status 0x%02x", status);
1657
1658 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1659}
1660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001661static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001662 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001663{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001664 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001665 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001666 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001667 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 -05001668 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001669 int err, found;
1670
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001671 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001672
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001673 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001674
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001675 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001676 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001677 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001678 goto unlock;
1679 }
1680
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001681 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1682 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001683
Johan Hedberg24b78d02012-02-23 23:24:30 +02001684 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001685 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001686 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001687 goto unlock;
1688 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001689
Johan Hedberg9246a862012-02-23 21:33:16 +02001690 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001691 }
1692
1693 found = 0;
1694
Johan Hedberg056341c2013-01-27 00:31:30 +02001695 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001696 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1697 continue;
1698
1699 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001700 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001701 found++;
1702 }
1703
1704 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001705 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001706 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001707 goto unlock;
1708 }
1709
Johan Hedberg9246a862012-02-23 21:33:16 +02001710update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001711 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001712
Johan Hedberg890ea892013-03-15 17:06:52 -05001713 update_class(&req);
1714 update_eir(&req);
1715
Johan Hedberg92da6092013-03-15 17:06:55 -05001716 err = hci_req_run(&req, remove_uuid_complete);
1717 if (err < 0) {
1718 if (err != -ENODATA)
1719 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001721 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001723 goto unlock;
1724 }
1725
1726 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001727 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001728 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001729 goto unlock;
1730 }
1731
1732 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001733
1734unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001735 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001736 return err;
1737}
1738
Johan Hedberg92da6092013-03-15 17:06:55 -05001739static void set_class_complete(struct hci_dev *hdev, u8 status)
1740{
1741 BT_DBG("status 0x%02x", status);
1742
1743 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1744}
1745
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001746static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001747 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001748{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001749 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001750 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001751 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001752 int err;
1753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001754 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001755
Johan Hedberg56f87902013-10-02 13:43:13 +03001756 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001757 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1758 MGMT_STATUS_NOT_SUPPORTED);
1759
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001760 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001761
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001762 if (pending_eir_or_class(hdev)) {
1763 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1764 MGMT_STATUS_BUSY);
1765 goto unlock;
1766 }
1767
1768 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1769 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1770 MGMT_STATUS_INVALID_PARAMS);
1771 goto unlock;
1772 }
1773
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001774 hdev->major_class = cp->major;
1775 hdev->minor_class = cp->minor;
1776
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001777 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001778 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001779 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001780 goto unlock;
1781 }
1782
Johan Hedberg890ea892013-03-15 17:06:52 -05001783 hci_req_init(&req, hdev);
1784
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001785 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001786 hci_dev_unlock(hdev);
1787 cancel_delayed_work_sync(&hdev->service_cache);
1788 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001789 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001790 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001791
Johan Hedberg890ea892013-03-15 17:06:52 -05001792 update_class(&req);
1793
Johan Hedberg92da6092013-03-15 17:06:55 -05001794 err = hci_req_run(&req, set_class_complete);
1795 if (err < 0) {
1796 if (err != -ENODATA)
1797 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001798
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001799 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001800 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001801 goto unlock;
1802 }
1803
1804 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001805 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001806 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001807 goto unlock;
1808 }
1809
1810 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001811
Johan Hedbergb5235a62012-02-21 14:32:24 +02001812unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001813 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001814 return err;
1815}
1816
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001817static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001818 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001819{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001820 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001821 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001822 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001823
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001824 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001825
Johan Hedberg86742e12011-11-07 23:13:38 +02001826 expected_len = sizeof(*cp) + key_count *
1827 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001828 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001829 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001830 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001831 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001832 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001833 }
1834
Johan Hedberg4ae14302013-01-20 14:27:13 +02001835 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1836 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1837 MGMT_STATUS_INVALID_PARAMS);
1838
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001839 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001840 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001841
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001842 for (i = 0; i < key_count; i++) {
1843 struct mgmt_link_key_info *key = &cp->keys[i];
1844
1845 if (key->addr.type != BDADDR_BREDR)
1846 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1847 MGMT_STATUS_INVALID_PARAMS);
1848 }
1849
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001850 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001851
1852 hci_link_keys_clear(hdev);
1853
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001854 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001855 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001856 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001857 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001858
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001859 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001860 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001861
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001862 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001863 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001864 }
1865
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001866 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001867
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001868 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001869
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001870 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001871}
1872
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001873static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001874 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001875{
1876 struct mgmt_ev_device_unpaired ev;
1877
1878 bacpy(&ev.addr.bdaddr, bdaddr);
1879 ev.addr.type = addr_type;
1880
1881 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001882 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001883}
1884
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001885static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001886 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001887{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001888 struct mgmt_cp_unpair_device *cp = data;
1889 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001890 struct hci_cp_disconnect dc;
1891 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001892 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001893 int err;
1894
Johan Hedberga8a1d192011-11-10 15:54:38 +02001895 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001896 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1897 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001898
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001899 if (!bdaddr_type_is_valid(cp->addr.type))
1900 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1901 MGMT_STATUS_INVALID_PARAMS,
1902 &rp, sizeof(rp));
1903
Johan Hedberg118da702013-01-20 14:27:20 +02001904 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1905 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1906 MGMT_STATUS_INVALID_PARAMS,
1907 &rp, sizeof(rp));
1908
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001909 hci_dev_lock(hdev);
1910
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001911 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001912 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001913 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001914 goto unlock;
1915 }
1916
Andre Guedes591f47f2012-04-24 21:02:49 -03001917 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001918 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1919 else
1920 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001921
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001922 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001923 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001924 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001925 goto unlock;
1926 }
1927
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001928 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001929 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001930 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001931 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001932 else
1933 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001934 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001935 } else {
1936 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001937 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001938
Johan Hedberga8a1d192011-11-10 15:54:38 +02001939 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001940 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001941 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001942 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001943 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001944 }
1945
Johan Hedberg124f6e32012-02-09 13:50:12 +02001946 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001947 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001948 if (!cmd) {
1949 err = -ENOMEM;
1950 goto unlock;
1951 }
1952
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001953 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001954 dc.reason = 0x13; /* Remote User Terminated Connection */
1955 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1956 if (err < 0)
1957 mgmt_pending_remove(cmd);
1958
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001959unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001960 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001961 return err;
1962}
1963
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001964static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001965 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001966{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001967 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001968 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001969 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001970 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001971 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001972 int err;
1973
1974 BT_DBG("");
1975
Johan Hedberg06a63b12013-01-20 14:27:21 +02001976 memset(&rp, 0, sizeof(rp));
1977 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1978 rp.addr.type = cp->addr.type;
1979
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001980 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001981 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1982 MGMT_STATUS_INVALID_PARAMS,
1983 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001985 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001986
1987 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001988 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1989 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001990 goto failed;
1991 }
1992
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001993 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001994 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1995 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001996 goto failed;
1997 }
1998
Andre Guedes591f47f2012-04-24 21:02:49 -03001999 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002000 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2001 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002002 else
2003 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002004
Vishal Agarwalf9607272012-06-13 05:32:43 +05302005 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002006 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2007 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002008 goto failed;
2009 }
2010
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002011 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002012 if (!cmd) {
2013 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002014 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002015 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002016
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002017 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002018 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002019
2020 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2021 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002022 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002023
2024failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002025 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002026 return err;
2027}
2028
Andre Guedes57c14772012-04-24 21:02:50 -03002029static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002030{
2031 switch (link_type) {
2032 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002033 switch (addr_type) {
2034 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002035 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002036
Johan Hedberg48264f02011-11-09 13:58:58 +02002037 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002038 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002039 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002040 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002041
Johan Hedberg4c659c32011-11-07 23:13:39 +02002042 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002043 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002044 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002045 }
2046}
2047
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002048static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2049 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002050{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002051 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002052 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002053 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002054 int err;
2055 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002056
2057 BT_DBG("");
2058
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002059 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002060
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002061 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002062 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002063 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002064 goto unlock;
2065 }
2066
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002067 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002068 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2069 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002070 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002071 }
2072
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002073 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002074 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002075 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002076 err = -ENOMEM;
2077 goto unlock;
2078 }
2079
Johan Hedberg2784eb42011-01-21 13:56:35 +02002080 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002081 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002082 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2083 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002084 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002085 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002086 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002087 continue;
2088 i++;
2089 }
2090
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002091 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002092
Johan Hedberg4c659c32011-11-07 23:13:39 +02002093 /* Recalculate length in case of filtered SCO connections, etc */
2094 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002096 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002097 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002098
Johan Hedberga38528f2011-01-22 06:46:43 +02002099 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002100
2101unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002102 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002103 return err;
2104}
2105
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002106static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002107 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002108{
2109 struct pending_cmd *cmd;
2110 int err;
2111
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002112 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002113 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002114 if (!cmd)
2115 return -ENOMEM;
2116
Johan Hedbergd8457692012-02-17 14:24:57 +02002117 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002118 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002119 if (err < 0)
2120 mgmt_pending_remove(cmd);
2121
2122 return err;
2123}
2124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002125static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002126 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002127{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002128 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002129 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002130 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002131 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002132 int err;
2133
2134 BT_DBG("");
2135
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002136 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002137
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002138 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002139 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002140 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002141 goto failed;
2142 }
2143
Johan Hedbergd8457692012-02-17 14:24:57 +02002144 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002145 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002146 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002147 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002148 goto failed;
2149 }
2150
2151 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002152 struct mgmt_cp_pin_code_neg_reply ncp;
2153
2154 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002155
2156 BT_ERR("PIN code is not 16 bytes long");
2157
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002158 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002159 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002160 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002161 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002162
2163 goto failed;
2164 }
2165
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002166 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002167 if (!cmd) {
2168 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002169 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002170 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002171
Johan Hedbergd8457692012-02-17 14:24:57 +02002172 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002173 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002174 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002175
2176 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2177 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002178 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179
2180failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002181 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002182 return err;
2183}
2184
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002185static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2186 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002187{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002188 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002189
2190 BT_DBG("");
2191
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002192 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002193
2194 hdev->io_capability = cp->io_capability;
2195
2196 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002197 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002198
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002199 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002200
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2202 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002203}
2204
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002205static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002206{
2207 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002208 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002209
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002210 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002211 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2212 continue;
2213
Johan Hedberge9a416b2011-02-19 12:05:56 -03002214 if (cmd->user_data != conn)
2215 continue;
2216
2217 return cmd;
2218 }
2219
2220 return NULL;
2221}
2222
2223static void pairing_complete(struct pending_cmd *cmd, u8 status)
2224{
2225 struct mgmt_rp_pair_device rp;
2226 struct hci_conn *conn = cmd->user_data;
2227
Johan Hedbergba4e5642011-11-11 00:07:34 +02002228 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002229 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002230
Johan Hedbergaee9b212012-02-18 15:07:59 +02002231 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002232 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002233
2234 /* So we don't get further callbacks for this connection */
2235 conn->connect_cfm_cb = NULL;
2236 conn->security_cfm_cb = NULL;
2237 conn->disconn_cfm_cb = NULL;
2238
David Herrmann76a68ba2013-04-06 20:28:37 +02002239 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002240
Johan Hedberga664b5b2011-02-19 12:06:02 -03002241 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002242}
2243
2244static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2245{
2246 struct pending_cmd *cmd;
2247
2248 BT_DBG("status %u", status);
2249
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002250 cmd = find_pairing(conn);
2251 if (!cmd)
2252 BT_DBG("Unable to find a pending command");
2253 else
Johan Hedberge2113262012-02-18 15:20:03 +02002254 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002255}
2256
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302257static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2258{
2259 struct pending_cmd *cmd;
2260
2261 BT_DBG("status %u", status);
2262
2263 if (!status)
2264 return;
2265
2266 cmd = find_pairing(conn);
2267 if (!cmd)
2268 BT_DBG("Unable to find a pending command");
2269 else
2270 pairing_complete(cmd, mgmt_status(status));
2271}
2272
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002273static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002274 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002275{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002276 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002277 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002278 struct pending_cmd *cmd;
2279 u8 sec_level, auth_type;
2280 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002281 int err;
2282
2283 BT_DBG("");
2284
Szymon Jancf950a30e2013-01-18 12:48:07 +01002285 memset(&rp, 0, sizeof(rp));
2286 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2287 rp.addr.type = cp->addr.type;
2288
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002289 if (!bdaddr_type_is_valid(cp->addr.type))
2290 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2291 MGMT_STATUS_INVALID_PARAMS,
2292 &rp, sizeof(rp));
2293
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002294 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002295
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002296 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002297 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2298 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002299 goto unlock;
2300 }
2301
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002302 sec_level = BT_SECURITY_MEDIUM;
2303 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002304 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002305 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002306 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002307
Andre Guedes591f47f2012-04-24 21:02:49 -03002308 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002309 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2310 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002311 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002312 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2313 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002314
Ville Tervo30e76272011-02-22 16:10:53 -03002315 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002316 int status;
2317
2318 if (PTR_ERR(conn) == -EBUSY)
2319 status = MGMT_STATUS_BUSY;
2320 else
2321 status = MGMT_STATUS_CONNECT_FAILED;
2322
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002323 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002324 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002325 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002326 goto unlock;
2327 }
2328
2329 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002330 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002331 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002332 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002333 goto unlock;
2334 }
2335
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002336 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002337 if (!cmd) {
2338 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002339 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002340 goto unlock;
2341 }
2342
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002343 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002344 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002345 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302346 else
2347 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002348
Johan Hedberge9a416b2011-02-19 12:05:56 -03002349 conn->security_cfm_cb = pairing_complete_cb;
2350 conn->disconn_cfm_cb = pairing_complete_cb;
2351 conn->io_capability = cp->io_cap;
2352 cmd->user_data = conn;
2353
2354 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002355 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002356 pairing_complete(cmd, 0);
2357
2358 err = 0;
2359
2360unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002362 return err;
2363}
2364
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002365static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2366 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002367{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002368 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002369 struct pending_cmd *cmd;
2370 struct hci_conn *conn;
2371 int err;
2372
2373 BT_DBG("");
2374
Johan Hedberg28424702012-02-02 04:02:29 +02002375 hci_dev_lock(hdev);
2376
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002377 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002378 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002379 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002380 goto unlock;
2381 }
2382
Johan Hedberg28424702012-02-02 04:02:29 +02002383 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2384 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002385 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002386 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002387 goto unlock;
2388 }
2389
2390 conn = cmd->user_data;
2391
2392 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002393 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002394 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002395 goto unlock;
2396 }
2397
2398 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2399
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002400 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002401 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002402unlock:
2403 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002404 return err;
2405}
2406
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002407static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002408 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002409 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002410{
Johan Hedberga5c29682011-02-19 12:05:57 -03002411 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002412 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002413 int err;
2414
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002415 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002416
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002417 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002418 err = cmd_complete(sk, hdev->id, mgmt_op,
2419 MGMT_STATUS_NOT_POWERED, addr,
2420 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002421 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002422 }
2423
Johan Hedberg1707c602013-03-15 17:07:15 -05002424 if (addr->type == BDADDR_BREDR)
2425 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002426 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002427 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002428
Johan Hedberg272d90d2012-02-09 15:26:12 +02002429 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002430 err = cmd_complete(sk, hdev->id, mgmt_op,
2431 MGMT_STATUS_NOT_CONNECTED, addr,
2432 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002433 goto done;
2434 }
2435
Johan Hedberg1707c602013-03-15 17:07:15 -05002436 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002437 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002438 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002439
Brian Gix5fe57d92011-12-21 16:12:13 -08002440 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002441 err = cmd_complete(sk, hdev->id, mgmt_op,
2442 MGMT_STATUS_SUCCESS, addr,
2443 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002444 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002445 err = cmd_complete(sk, hdev->id, mgmt_op,
2446 MGMT_STATUS_FAILED, addr,
2447 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002448
Brian Gix47c15e22011-11-16 13:53:14 -08002449 goto done;
2450 }
2451
Johan Hedberg1707c602013-03-15 17:07:15 -05002452 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002453 if (!cmd) {
2454 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002455 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002456 }
2457
Brian Gix0df4c182011-11-16 13:53:13 -08002458 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002459 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2460 struct hci_cp_user_passkey_reply cp;
2461
Johan Hedberg1707c602013-03-15 17:07:15 -05002462 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002463 cp.passkey = passkey;
2464 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2465 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002466 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2467 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002468
Johan Hedberga664b5b2011-02-19 12:06:02 -03002469 if (err < 0)
2470 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002471
Brian Gix0df4c182011-11-16 13:53:13 -08002472done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002473 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002474 return err;
2475}
2476
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302477static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2478 void *data, u16 len)
2479{
2480 struct mgmt_cp_pin_code_neg_reply *cp = data;
2481
2482 BT_DBG("");
2483
Johan Hedberg1707c602013-03-15 17:07:15 -05002484 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302485 MGMT_OP_PIN_CODE_NEG_REPLY,
2486 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2487}
2488
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002489static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2490 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002491{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002492 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002493
2494 BT_DBG("");
2495
2496 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002497 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002498 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002499
Johan Hedberg1707c602013-03-15 17:07:15 -05002500 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002501 MGMT_OP_USER_CONFIRM_REPLY,
2502 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002503}
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002507{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002508 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002509
2510 BT_DBG("");
2511
Johan Hedberg1707c602013-03-15 17:07:15 -05002512 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002513 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2514 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002515}
2516
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002517static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2518 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002519{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002520 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002521
2522 BT_DBG("");
2523
Johan Hedberg1707c602013-03-15 17:07:15 -05002524 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002525 MGMT_OP_USER_PASSKEY_REPLY,
2526 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002527}
2528
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002529static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002530 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002531{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002532 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002533
2534 BT_DBG("");
2535
Johan Hedberg1707c602013-03-15 17:07:15 -05002536 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002537 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2538 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002539}
2540
Johan Hedberg13928972013-03-15 17:07:00 -05002541static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002542{
Johan Hedberg13928972013-03-15 17:07:00 -05002543 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002544 struct hci_cp_write_local_name cp;
2545
Johan Hedberg13928972013-03-15 17:07:00 -05002546 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002547
Johan Hedberg890ea892013-03-15 17:06:52 -05002548 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002549}
2550
Johan Hedberg13928972013-03-15 17:07:00 -05002551static void set_name_complete(struct hci_dev *hdev, u8 status)
2552{
2553 struct mgmt_cp_set_local_name *cp;
2554 struct pending_cmd *cmd;
2555
2556 BT_DBG("status 0x%02x", status);
2557
2558 hci_dev_lock(hdev);
2559
2560 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2561 if (!cmd)
2562 goto unlock;
2563
2564 cp = cmd->param;
2565
2566 if (status)
2567 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2568 mgmt_status(status));
2569 else
2570 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2571 cp, sizeof(*cp));
2572
2573 mgmt_pending_remove(cmd);
2574
2575unlock:
2576 hci_dev_unlock(hdev);
2577}
2578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002579static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002581{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002582 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002583 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002584 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002585 int err;
2586
2587 BT_DBG("");
2588
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002589 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002590
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002591 /* If the old values are the same as the new ones just return a
2592 * direct command complete event.
2593 */
2594 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2595 !memcmp(hdev->short_name, cp->short_name,
2596 sizeof(hdev->short_name))) {
2597 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2598 data, len);
2599 goto failed;
2600 }
2601
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002602 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002603
Johan Hedbergb5235a62012-02-21 14:32:24 +02002604 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002605 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002606
2607 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002608 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002609 if (err < 0)
2610 goto failed;
2611
2612 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002613 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002614
Johan Hedbergb5235a62012-02-21 14:32:24 +02002615 goto failed;
2616 }
2617
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002618 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002619 if (!cmd) {
2620 err = -ENOMEM;
2621 goto failed;
2622 }
2623
Johan Hedberg13928972013-03-15 17:07:00 -05002624 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2625
Johan Hedberg890ea892013-03-15 17:06:52 -05002626 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002627
2628 if (lmp_bredr_capable(hdev)) {
2629 update_name(&req);
2630 update_eir(&req);
2631 }
2632
2633 if (lmp_le_capable(hdev))
2634 hci_update_ad(&req);
2635
Johan Hedberg13928972013-03-15 17:07:00 -05002636 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002637 if (err < 0)
2638 mgmt_pending_remove(cmd);
2639
2640failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002641 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002642 return err;
2643}
2644
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002645static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002646 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002647{
Szymon Jancc35938b2011-03-22 13:12:21 +01002648 struct pending_cmd *cmd;
2649 int err;
2650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002651 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002652
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002653 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002654
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002655 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002656 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002657 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002658 goto unlock;
2659 }
2660
Andre Guedes9a1a1992012-07-24 15:03:48 -03002661 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002663 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002664 goto unlock;
2665 }
2666
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002667 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002668 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002669 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002670 goto unlock;
2671 }
2672
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002673 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002674 if (!cmd) {
2675 err = -ENOMEM;
2676 goto unlock;
2677 }
2678
2679 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2680 if (err < 0)
2681 mgmt_pending_remove(cmd);
2682
2683unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002684 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002685 return err;
2686}
2687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002688static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002689 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002690{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002691 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002692 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002693 int err;
2694
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002695 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002697 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002698
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002699 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002701 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002702 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002703 else
Szymon Janca6785be2012-12-13 15:11:21 +01002704 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002705
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002706 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002707 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002708
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002709 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002710 return err;
2711}
2712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002713static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002714 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002715{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002716 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002717 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002718 int err;
2719
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002720 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002721
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002722 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002723
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002724 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002725 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002726 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002727 else
Szymon Janca6785be2012-12-13 15:11:21 +01002728 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002730 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002731 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002732
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002733 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002734 return err;
2735}
2736
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002737static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2738{
2739 struct pending_cmd *cmd;
2740 u8 type;
2741 int err;
2742
2743 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2744
2745 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2746 if (!cmd)
2747 return -ENOENT;
2748
2749 type = hdev->discovery.type;
2750
2751 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2752 &type, sizeof(type));
2753 mgmt_pending_remove(cmd);
2754
2755 return err;
2756}
2757
Andre Guedes7c307722013-04-30 15:29:28 -03002758static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2759{
2760 BT_DBG("status %d", status);
2761
2762 if (status) {
2763 hci_dev_lock(hdev);
2764 mgmt_start_discovery_failed(hdev, status);
2765 hci_dev_unlock(hdev);
2766 return;
2767 }
2768
2769 hci_dev_lock(hdev);
2770 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2771 hci_dev_unlock(hdev);
2772
2773 switch (hdev->discovery.type) {
2774 case DISCOV_TYPE_LE:
2775 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002776 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002777 break;
2778
2779 case DISCOV_TYPE_INTERLEAVED:
2780 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002781 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002782 break;
2783
2784 case DISCOV_TYPE_BREDR:
2785 break;
2786
2787 default:
2788 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2789 }
2790}
2791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002792static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002793 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002794{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002795 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002796 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002797 struct hci_cp_le_set_scan_param param_cp;
2798 struct hci_cp_le_set_scan_enable enable_cp;
2799 struct hci_cp_inquiry inq_cp;
2800 struct hci_request req;
2801 /* General inquiry access code (GIAC) */
2802 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002803 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002804 int err;
2805
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002806 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002807
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002808 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002809
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002810 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002811 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002812 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002813 goto failed;
2814 }
2815
Andre Guedes642be6c2012-03-21 00:03:37 -03002816 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2817 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2818 MGMT_STATUS_BUSY);
2819 goto failed;
2820 }
2821
Johan Hedbergff9ef572012-01-04 14:23:45 +02002822 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002823 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002824 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002825 goto failed;
2826 }
2827
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002828 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002829 if (!cmd) {
2830 err = -ENOMEM;
2831 goto failed;
2832 }
2833
Andre Guedes4aab14e2012-02-17 20:39:36 -03002834 hdev->discovery.type = cp->type;
2835
Andre Guedes7c307722013-04-30 15:29:28 -03002836 hci_req_init(&req, hdev);
2837
Andre Guedes4aab14e2012-02-17 20:39:36 -03002838 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002839 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002840 status = mgmt_bredr_support(hdev);
2841 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002842 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002843 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002844 mgmt_pending_remove(cmd);
2845 goto failed;
2846 }
2847
Andre Guedes7c307722013-04-30 15:29:28 -03002848 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2849 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2850 MGMT_STATUS_BUSY);
2851 mgmt_pending_remove(cmd);
2852 goto failed;
2853 }
2854
2855 hci_inquiry_cache_flush(hdev);
2856
2857 memset(&inq_cp, 0, sizeof(inq_cp));
2858 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002859 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002860 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002861 break;
2862
2863 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002864 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002865 status = mgmt_le_support(hdev);
2866 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002867 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002868 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002869 mgmt_pending_remove(cmd);
2870 goto failed;
2871 }
2872
Andre Guedes7c307722013-04-30 15:29:28 -03002873 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002874 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002875 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2876 MGMT_STATUS_NOT_SUPPORTED);
2877 mgmt_pending_remove(cmd);
2878 goto failed;
2879 }
2880
Andre Guedes7c307722013-04-30 15:29:28 -03002881 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2882 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2883 MGMT_STATUS_REJECTED);
2884 mgmt_pending_remove(cmd);
2885 goto failed;
2886 }
2887
2888 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2889 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2890 MGMT_STATUS_BUSY);
2891 mgmt_pending_remove(cmd);
2892 goto failed;
2893 }
2894
2895 memset(&param_cp, 0, sizeof(param_cp));
2896 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002897 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2898 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002899 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2900 &param_cp);
2901
2902 memset(&enable_cp, 0, sizeof(enable_cp));
2903 enable_cp.enable = LE_SCAN_ENABLE;
2904 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2905 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2906 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002907 break;
2908
Andre Guedesf39799f2012-02-17 20:39:35 -03002909 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002910 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2911 MGMT_STATUS_INVALID_PARAMS);
2912 mgmt_pending_remove(cmd);
2913 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002914 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002915
Andre Guedes7c307722013-04-30 15:29:28 -03002916 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002917 if (err < 0)
2918 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002919 else
2920 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002921
2922failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002923 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002924 return err;
2925}
2926
Andre Guedes1183fdc2013-04-30 15:29:35 -03002927static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2928{
2929 struct pending_cmd *cmd;
2930 int err;
2931
2932 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2933 if (!cmd)
2934 return -ENOENT;
2935
2936 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2937 &hdev->discovery.type, sizeof(hdev->discovery.type));
2938 mgmt_pending_remove(cmd);
2939
2940 return err;
2941}
2942
Andre Guedes0e05bba2013-04-30 15:29:33 -03002943static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2944{
2945 BT_DBG("status %d", status);
2946
2947 hci_dev_lock(hdev);
2948
2949 if (status) {
2950 mgmt_stop_discovery_failed(hdev, status);
2951 goto unlock;
2952 }
2953
2954 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2955
2956unlock:
2957 hci_dev_unlock(hdev);
2958}
2959
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002960static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002961 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002962{
Johan Hedbergd9306502012-02-20 23:25:18 +02002963 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002964 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002965 struct hci_cp_remote_name_req_cancel cp;
2966 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002967 struct hci_request req;
2968 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002969 int err;
2970
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002971 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002972
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002973 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002974
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002975 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002976 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002977 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2978 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002979 goto unlock;
2980 }
2981
2982 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002983 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002984 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2985 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002986 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002987 }
2988
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002989 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002990 if (!cmd) {
2991 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002992 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002993 }
2994
Andre Guedes0e05bba2013-04-30 15:29:33 -03002995 hci_req_init(&req, hdev);
2996
Andre Guedese0d9727e2012-03-20 15:15:36 -03002997 switch (hdev->discovery.state) {
2998 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002999 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3000 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3001 } else {
3002 cancel_delayed_work(&hdev->le_scan_disable);
3003
3004 memset(&enable_cp, 0, sizeof(enable_cp));
3005 enable_cp.enable = LE_SCAN_DISABLE;
3006 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3007 sizeof(enable_cp), &enable_cp);
3008 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003009
Andre Guedese0d9727e2012-03-20 15:15:36 -03003010 break;
3011
3012 case DISCOVERY_RESOLVING:
3013 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003014 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003015 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003016 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003017 err = cmd_complete(sk, hdev->id,
3018 MGMT_OP_STOP_DISCOVERY, 0,
3019 &mgmt_cp->type,
3020 sizeof(mgmt_cp->type));
3021 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3022 goto unlock;
3023 }
3024
3025 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003026 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3027 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003028
3029 break;
3030
3031 default:
3032 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003033
3034 mgmt_pending_remove(cmd);
3035 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3036 MGMT_STATUS_FAILED, &mgmt_cp->type,
3037 sizeof(mgmt_cp->type));
3038 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003039 }
3040
Andre Guedes0e05bba2013-04-30 15:29:33 -03003041 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003042 if (err < 0)
3043 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003044 else
3045 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003046
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003047unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003048 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003049 return err;
3050}
3051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003052static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003053 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003054{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003055 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003056 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003057 int err;
3058
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003059 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003060
Johan Hedberg561aafb2012-01-04 13:31:59 +02003061 hci_dev_lock(hdev);
3062
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003063 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003064 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003065 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003066 goto failed;
3067 }
3068
Johan Hedberga198e7b2012-02-17 14:27:06 +02003069 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003070 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003071 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003072 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003073 goto failed;
3074 }
3075
3076 if (cp->name_known) {
3077 e->name_state = NAME_KNOWN;
3078 list_del(&e->list);
3079 } else {
3080 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003081 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003082 }
3083
Johan Hedberge3846622013-01-09 15:29:33 +02003084 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3085 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003086
3087failed:
3088 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003089 return err;
3090}
3091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003092static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003093 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003094{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003095 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003096 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003097 int err;
3098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003099 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003100
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003101 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003102 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3103 MGMT_STATUS_INVALID_PARAMS,
3104 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003105
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003106 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003107
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003108 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003109 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003110 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003111 else
Szymon Janca6785be2012-12-13 15:11:21 +01003112 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003114 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003115 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003116
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003117 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003118
3119 return err;
3120}
3121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003122static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003123 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003124{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003125 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003126 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003127 int err;
3128
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003129 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003130
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003131 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003132 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3133 MGMT_STATUS_INVALID_PARAMS,
3134 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003135
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003136 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003137
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003138 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003139 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003140 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003141 else
Szymon Janca6785be2012-12-13 15:11:21 +01003142 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003144 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003146
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003147 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003148
3149 return err;
3150}
3151
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003152static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3153 u16 len)
3154{
3155 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003156 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003157 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003158 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003159
3160 BT_DBG("%s", hdev->name);
3161
Szymon Jancc72d4b82012-03-16 16:02:57 +01003162 source = __le16_to_cpu(cp->source);
3163
3164 if (source > 0x0002)
3165 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3166 MGMT_STATUS_INVALID_PARAMS);
3167
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003168 hci_dev_lock(hdev);
3169
Szymon Jancc72d4b82012-03-16 16:02:57 +01003170 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003171 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3172 hdev->devid_product = __le16_to_cpu(cp->product);
3173 hdev->devid_version = __le16_to_cpu(cp->version);
3174
3175 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3176
Johan Hedberg890ea892013-03-15 17:06:52 -05003177 hci_req_init(&req, hdev);
3178 update_eir(&req);
3179 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003180
3181 hci_dev_unlock(hdev);
3182
3183 return err;
3184}
3185
Johan Hedberg4375f102013-09-25 13:26:10 +03003186static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3187{
3188 struct cmd_lookup match = { NULL, hdev };
3189
3190 if (status) {
3191 u8 mgmt_err = mgmt_status(status);
3192
3193 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3194 cmd_status_rsp, &mgmt_err);
3195 return;
3196 }
3197
3198 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3199 &match);
3200
3201 new_settings(hdev, match.sk);
3202
3203 if (match.sk)
3204 sock_put(match.sk);
3205}
3206
3207static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3208{
3209 struct mgmt_mode *cp = data;
3210 struct pending_cmd *cmd;
3211 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003212 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003213 int err;
3214
3215 BT_DBG("request for %s", hdev->name);
3216
Johan Hedberge6fe7982013-10-02 15:45:22 +03003217 status = mgmt_le_support(hdev);
3218 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003219 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003220 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003221
3222 if (cp->val != 0x00 && cp->val != 0x01)
3223 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3224 MGMT_STATUS_INVALID_PARAMS);
3225
3226 hci_dev_lock(hdev);
3227
3228 val = !!cp->val;
3229 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3230
3231 if (!hdev_is_powered(hdev) || val == enabled) {
3232 bool changed = false;
3233
3234 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3235 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3236 changed = true;
3237 }
3238
3239 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3240 if (err < 0)
3241 goto unlock;
3242
3243 if (changed)
3244 err = new_settings(hdev, sk);
3245
3246 goto unlock;
3247 }
3248
3249 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3250 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3251 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3252 MGMT_STATUS_BUSY);
3253 goto unlock;
3254 }
3255
3256 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3257 if (!cmd) {
3258 err = -ENOMEM;
3259 goto unlock;
3260 }
3261
3262 hci_req_init(&req, hdev);
3263
3264 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3265
3266 err = hci_req_run(&req, set_advertising_complete);
3267 if (err < 0)
3268 mgmt_pending_remove(cmd);
3269
3270unlock:
3271 hci_dev_unlock(hdev);
3272 return err;
3273}
3274
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003275static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3276 void *data, u16 len)
3277{
3278 struct mgmt_cp_set_static_address *cp = data;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003279 u8 status;
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003280 int err;
3281
3282 BT_DBG("%s", hdev->name);
3283
Johan Hedberge6fe7982013-10-02 15:45:22 +03003284 status = mgmt_le_support(hdev);
3285 if (status)
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003286 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003287 status);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003288
3289 if (hdev_is_powered(hdev))
3290 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3291 MGMT_STATUS_REJECTED);
3292
3293 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3294 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3295 return cmd_status(sk, hdev->id,
3296 MGMT_OP_SET_STATIC_ADDRESS,
3297 MGMT_STATUS_INVALID_PARAMS);
3298
3299 /* Two most significant bits shall be set */
3300 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3301 return cmd_status(sk, hdev->id,
3302 MGMT_OP_SET_STATIC_ADDRESS,
3303 MGMT_STATUS_INVALID_PARAMS);
3304 }
3305
3306 hci_dev_lock(hdev);
3307
3308 bacpy(&hdev->static_addr, &cp->bdaddr);
3309
3310 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3311
3312 hci_dev_unlock(hdev);
3313
3314 return err;
3315}
3316
Johan Hedberg33e38b32013-03-15 17:07:05 -05003317static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3318{
3319 struct pending_cmd *cmd;
3320
3321 BT_DBG("status 0x%02x", status);
3322
3323 hci_dev_lock(hdev);
3324
3325 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3326 if (!cmd)
3327 goto unlock;
3328
3329 if (status) {
3330 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3331 mgmt_status(status));
3332 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003333 struct mgmt_mode *cp = cmd->param;
3334
3335 if (cp->val)
3336 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3337 else
3338 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3339
Johan Hedberg33e38b32013-03-15 17:07:05 -05003340 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3341 new_settings(hdev, cmd->sk);
3342 }
3343
3344 mgmt_pending_remove(cmd);
3345
3346unlock:
3347 hci_dev_unlock(hdev);
3348}
3349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003350static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003351 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003352{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003353 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003354 struct pending_cmd *cmd;
3355 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003356 int err;
3357
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003358 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003359
Johan Hedberg56f87902013-10-02 13:43:13 +03003360 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3361 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003362 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3363 MGMT_STATUS_NOT_SUPPORTED);
3364
Johan Hedberga7e80f22013-01-09 16:05:19 +02003365 if (cp->val != 0x00 && cp->val != 0x01)
3366 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3367 MGMT_STATUS_INVALID_PARAMS);
3368
Johan Hedberg5400c042012-02-21 16:40:33 +02003369 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003370 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003371 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003372
3373 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003374 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003375 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003376
3377 hci_dev_lock(hdev);
3378
Johan Hedberg05cbf292013-03-15 17:07:07 -05003379 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3380 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3381 MGMT_STATUS_BUSY);
3382 goto unlock;
3383 }
3384
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003385 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3386 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3387 hdev);
3388 goto unlock;
3389 }
3390
Johan Hedberg33e38b32013-03-15 17:07:05 -05003391 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3392 data, len);
3393 if (!cmd) {
3394 err = -ENOMEM;
3395 goto unlock;
3396 }
3397
3398 hci_req_init(&req, hdev);
3399
Johan Hedberg406d7802013-03-15 17:07:09 -05003400 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003401
3402 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003403 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003404 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003406 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003407 }
3408
Johan Hedberg33e38b32013-03-15 17:07:05 -05003409unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003410 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003411
Antti Julkuf6422ec2011-06-22 13:11:56 +03003412 return err;
3413}
3414
Johan Hedberg0663ca22013-10-02 13:43:14 +03003415static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3416{
3417 struct pending_cmd *cmd;
3418
3419 BT_DBG("status 0x%02x", status);
3420
3421 hci_dev_lock(hdev);
3422
3423 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3424 if (!cmd)
3425 goto unlock;
3426
3427 if (status) {
3428 u8 mgmt_err = mgmt_status(status);
3429
3430 /* We need to restore the flag if related HCI commands
3431 * failed.
3432 */
3433 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3434
3435 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3436 } else {
3437 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3438 new_settings(hdev, cmd->sk);
3439 }
3440
3441 mgmt_pending_remove(cmd);
3442
3443unlock:
3444 hci_dev_unlock(hdev);
3445}
3446
3447static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3448{
3449 struct mgmt_mode *cp = data;
3450 struct pending_cmd *cmd;
3451 struct hci_request req;
3452 int err;
3453
3454 BT_DBG("request for %s", hdev->name);
3455
3456 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3457 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3458 MGMT_STATUS_NOT_SUPPORTED);
3459
3460 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3461 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3462 MGMT_STATUS_REJECTED);
3463
3464 if (cp->val != 0x00 && cp->val != 0x01)
3465 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3466 MGMT_STATUS_INVALID_PARAMS);
3467
3468 hci_dev_lock(hdev);
3469
3470 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3471 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3472 goto unlock;
3473 }
3474
3475 if (!hdev_is_powered(hdev)) {
3476 if (!cp->val) {
3477 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3478 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3479 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3480 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3481 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3482 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3483 }
3484
3485 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3486
3487 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3488 if (err < 0)
3489 goto unlock;
3490
3491 err = new_settings(hdev, sk);
3492 goto unlock;
3493 }
3494
3495 /* Reject disabling when powered on */
3496 if (!cp->val) {
3497 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3498 MGMT_STATUS_REJECTED);
3499 goto unlock;
3500 }
3501
3502 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3503 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3504 MGMT_STATUS_BUSY);
3505 goto unlock;
3506 }
3507
3508 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3509 if (!cmd) {
3510 err = -ENOMEM;
3511 goto unlock;
3512 }
3513
3514 /* We need to flip the bit already here so that hci_update_ad
3515 * generates the correct flags.
3516 */
3517 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3518
3519 hci_req_init(&req, hdev);
3520 hci_update_ad(&req);
3521 err = hci_req_run(&req, set_bredr_complete);
3522 if (err < 0)
3523 mgmt_pending_remove(cmd);
3524
3525unlock:
3526 hci_dev_unlock(hdev);
3527 return err;
3528}
3529
Johan Hedberg3f706b72013-01-20 14:27:16 +02003530static bool ltk_is_valid(struct mgmt_ltk_info *key)
3531{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003532 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3533 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003534 if (key->master != 0x00 && key->master != 0x01)
3535 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003536 if (!bdaddr_type_is_le(key->addr.type))
3537 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003538 return true;
3539}
3540
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003541static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003542 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003543{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003544 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3545 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003546 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003547
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003548 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003549
3550 expected_len = sizeof(*cp) + key_count *
3551 sizeof(struct mgmt_ltk_info);
3552 if (expected_len != len) {
3553 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003554 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003555 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003556 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003557 }
3558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003559 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003560
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003561 for (i = 0; i < key_count; i++) {
3562 struct mgmt_ltk_info *key = &cp->keys[i];
3563
Johan Hedberg3f706b72013-01-20 14:27:16 +02003564 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003565 return cmd_status(sk, hdev->id,
3566 MGMT_OP_LOAD_LONG_TERM_KEYS,
3567 MGMT_STATUS_INVALID_PARAMS);
3568 }
3569
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003570 hci_dev_lock(hdev);
3571
3572 hci_smp_ltks_clear(hdev);
3573
3574 for (i = 0; i < key_count; i++) {
3575 struct mgmt_ltk_info *key = &cp->keys[i];
3576 u8 type;
3577
3578 if (key->master)
3579 type = HCI_SMP_LTK;
3580 else
3581 type = HCI_SMP_LTK_SLAVE;
3582
Hemant Gupta4596fde2012-04-16 14:57:40 +05303583 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003584 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003585 type, 0, key->authenticated, key->val,
3586 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003587 }
3588
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003589 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3590 NULL, 0);
3591
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003592 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003593
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003594 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003595}
3596
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003597static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003598 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3599 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003600 bool var_len;
3601 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003602} mgmt_handlers[] = {
3603 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003604 { read_version, false, MGMT_READ_VERSION_SIZE },
3605 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3606 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3607 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3608 { set_powered, false, MGMT_SETTING_SIZE },
3609 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3610 { set_connectable, false, MGMT_SETTING_SIZE },
3611 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3612 { set_pairable, false, MGMT_SETTING_SIZE },
3613 { set_link_security, false, MGMT_SETTING_SIZE },
3614 { set_ssp, false, MGMT_SETTING_SIZE },
3615 { set_hs, false, MGMT_SETTING_SIZE },
3616 { set_le, false, MGMT_SETTING_SIZE },
3617 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3618 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3619 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3620 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3621 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3622 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3623 { disconnect, false, MGMT_DISCONNECT_SIZE },
3624 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3625 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3626 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3627 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3628 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3629 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3630 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3631 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3632 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3633 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3634 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3635 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3636 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3637 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3638 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3639 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3640 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3641 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3642 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003643 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003644 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003645 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003646 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003647};
3648
3649
Johan Hedberg03811012010-12-08 00:21:06 +02003650int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3651{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003652 void *buf;
3653 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003654 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003655 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003656 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003657 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003658 int err;
3659
3660 BT_DBG("got %zu bytes", msglen);
3661
3662 if (msglen < sizeof(*hdr))
3663 return -EINVAL;
3664
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003665 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003666 if (!buf)
3667 return -ENOMEM;
3668
3669 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3670 err = -EFAULT;
3671 goto done;
3672 }
3673
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003674 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003675 opcode = __le16_to_cpu(hdr->opcode);
3676 index = __le16_to_cpu(hdr->index);
3677 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003678
3679 if (len != msglen - sizeof(*hdr)) {
3680 err = -EINVAL;
3681 goto done;
3682 }
3683
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003684 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003685 hdev = hci_dev_get(index);
3686 if (!hdev) {
3687 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003688 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003689 goto done;
3690 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003691
3692 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3693 err = cmd_status(sk, index, opcode,
3694 MGMT_STATUS_INVALID_INDEX);
3695 goto done;
3696 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003697 }
3698
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003699 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003700 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003701 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003702 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003703 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003704 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003705 }
3706
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003707 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003708 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003709 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003710 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003711 goto done;
3712 }
3713
Johan Hedbergbe22b542012-03-01 22:24:41 +02003714 handler = &mgmt_handlers[opcode];
3715
3716 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003717 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003718 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003719 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003720 goto done;
3721 }
3722
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003723 if (hdev)
3724 mgmt_init_hdev(sk, hdev);
3725
3726 cp = buf + sizeof(*hdr);
3727
Johan Hedbergbe22b542012-03-01 22:24:41 +02003728 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003729 if (err < 0)
3730 goto done;
3731
Johan Hedberg03811012010-12-08 00:21:06 +02003732 err = msglen;
3733
3734done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003735 if (hdev)
3736 hci_dev_put(hdev);
3737
Johan Hedberg03811012010-12-08 00:21:06 +02003738 kfree(buf);
3739 return err;
3740}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003741
Johan Hedberg744cf192011-11-08 20:40:14 +02003742int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003743{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003744 if (!mgmt_valid_hdev(hdev))
3745 return -ENOTSUPP;
3746
Johan Hedberg744cf192011-11-08 20:40:14 +02003747 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003748}
3749
Johan Hedberg744cf192011-11-08 20:40:14 +02003750int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003751{
Johan Hedberg5f159032012-03-02 03:13:19 +02003752 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003753
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003754 if (!mgmt_valid_hdev(hdev))
3755 return -ENOTSUPP;
3756
Johan Hedberg744cf192011-11-08 20:40:14 +02003757 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003758
Johan Hedberg744cf192011-11-08 20:40:14 +02003759 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003760}
3761
Johan Hedberg890ea892013-03-15 17:06:52 -05003762static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003763{
Johan Hedberg890ea892013-03-15 17:06:52 -05003764 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003765 u8 scan = 0;
3766
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003767 /* Ensure that fast connectable is disabled. This function will
3768 * not do anything if the page scan parameters are already what
3769 * they should be.
3770 */
3771 write_fast_connectable(req, false);
3772
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003773 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3774 scan |= SCAN_PAGE;
3775 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3776 scan |= SCAN_INQUIRY;
3777
Johan Hedberg890ea892013-03-15 17:06:52 -05003778 if (scan)
3779 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003780}
3781
Johan Hedberg229ab392013-03-15 17:06:53 -05003782static void powered_complete(struct hci_dev *hdev, u8 status)
3783{
3784 struct cmd_lookup match = { NULL, hdev };
3785
3786 BT_DBG("status 0x%02x", status);
3787
3788 hci_dev_lock(hdev);
3789
3790 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3791
3792 new_settings(hdev, match.sk);
3793
3794 hci_dev_unlock(hdev);
3795
3796 if (match.sk)
3797 sock_put(match.sk);
3798}
3799
Johan Hedberg70da6242013-03-15 17:06:51 -05003800static int powered_update_hci(struct hci_dev *hdev)
3801{
Johan Hedberg890ea892013-03-15 17:06:52 -05003802 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003803 u8 link_sec;
3804
Johan Hedberg890ea892013-03-15 17:06:52 -05003805 hci_req_init(&req, hdev);
3806
Johan Hedberg70da6242013-03-15 17:06:51 -05003807 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3808 !lmp_host_ssp_capable(hdev)) {
3809 u8 ssp = 1;
3810
Johan Hedberg890ea892013-03-15 17:06:52 -05003811 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003812 }
3813
Johan Hedbergc73eee92013-04-19 18:35:21 +03003814 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3815 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003816 struct hci_cp_write_le_host_supported cp;
3817
3818 cp.le = 1;
3819 cp.simul = lmp_le_br_capable(hdev);
3820
3821 /* Check first if we already have the right
3822 * host state (host features set)
3823 */
3824 if (cp.le != lmp_host_le_capable(hdev) ||
3825 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003826 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3827 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003828
3829 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3830 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003831 }
3832
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003833 if (lmp_le_capable(hdev)) {
3834 /* Set random address to static address if configured */
3835 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3836 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3837 &hdev->static_addr);
3838 }
3839
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003840 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3841 u8 adv = 0x01;
3842
3843 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3844 }
3845
Johan Hedberg70da6242013-03-15 17:06:51 -05003846 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3847 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003848 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3849 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003850
3851 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003852 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3853 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003854 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003855 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003856 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003857 }
3858
Johan Hedberg229ab392013-03-15 17:06:53 -05003859 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003860}
3861
Johan Hedberg744cf192011-11-08 20:40:14 +02003862int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003863{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003864 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003865 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3866 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003867 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003868
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003869 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3870 return 0;
3871
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003872 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003873 if (powered_update_hci(hdev) == 0)
3874 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003875
Johan Hedberg229ab392013-03-15 17:06:53 -05003876 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3877 &match);
3878 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003879 }
3880
Johan Hedberg229ab392013-03-15 17:06:53 -05003881 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3882 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3883
3884 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3885 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3886 zero_cod, sizeof(zero_cod), NULL);
3887
3888new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003889 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003890
3891 if (match.sk)
3892 sock_put(match.sk);
3893
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003894 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003895}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003896
Johan Hedberg96570ff2013-05-29 09:51:29 +03003897int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3898{
3899 struct pending_cmd *cmd;
3900 u8 status;
3901
3902 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3903 if (!cmd)
3904 return -ENOENT;
3905
3906 if (err == -ERFKILL)
3907 status = MGMT_STATUS_RFKILLED;
3908 else
3909 status = MGMT_STATUS_FAILED;
3910
3911 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3912
3913 mgmt_pending_remove(cmd);
3914
3915 return err;
3916}
3917
Johan Hedberg744cf192011-11-08 20:40:14 +02003918int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003919{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003920 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003921 bool changed = false;
3922 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003923
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003924 if (discoverable) {
3925 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3926 changed = true;
3927 } else {
3928 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3929 changed = true;
3930 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003931
Johan Hedberged9b5f22012-02-21 20:47:06 +02003932 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003933 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003934
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003935 if (changed)
3936 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003937
Johan Hedberg73f22f62010-12-29 16:00:25 +02003938 if (match.sk)
3939 sock_put(match.sk);
3940
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003941 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003942}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003943
Johan Hedberg744cf192011-11-08 20:40:14 +02003944int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003945{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003946 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003947 bool changed = false;
3948 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003949
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003950 if (connectable) {
3951 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3952 changed = true;
3953 } else {
3954 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3955 changed = true;
3956 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003957
Johan Hedberg2b76f452013-03-15 17:07:04 -05003958 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003959
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003960 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003961 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003962
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003963 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003964}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003965
Johan Hedberg744cf192011-11-08 20:40:14 +02003966int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003967{
Johan Hedbergca69b792011-11-11 18:10:00 +02003968 u8 mgmt_err = mgmt_status(status);
3969
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003970 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003971 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003972 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003973
3974 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003975 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003976 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003977
3978 return 0;
3979}
3980
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003981int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3982 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003983{
Johan Hedberg86742e12011-11-07 23:13:38 +02003984 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003985
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003986 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003987
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003988 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003989 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003990 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003991 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003992 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003993 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003994
Johan Hedberg744cf192011-11-08 20:40:14 +02003995 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003996}
Johan Hedbergf7520542011-01-20 12:34:39 +02003997
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003998int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3999{
4000 struct mgmt_ev_new_long_term_key ev;
4001
4002 memset(&ev, 0, sizeof(ev));
4003
4004 ev.store_hint = persistent;
4005 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004006 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004007 ev.key.authenticated = key->authenticated;
4008 ev.key.enc_size = key->enc_size;
4009 ev.key.ediv = key->ediv;
4010
4011 if (key->type == HCI_SMP_LTK)
4012 ev.key.master = 1;
4013
4014 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4015 memcpy(ev.key.val, key->val, sizeof(key->val));
4016
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004017 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4018 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004019}
4020
Johan Hedbergafc747a2012-01-15 18:11:07 +02004021int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004022 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4023 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004024{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004025 char buf[512];
4026 struct mgmt_ev_device_connected *ev = (void *) buf;
4027 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004028
Johan Hedbergb644ba32012-01-17 21:48:47 +02004029 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004030 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004031
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004032 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004033
Johan Hedbergb644ba32012-01-17 21:48:47 +02004034 if (name_len > 0)
4035 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004036 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004037
4038 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004039 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004040 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004041
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004042 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004043
4044 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004045 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004046}
4047
Johan Hedberg8962ee72011-01-20 12:40:27 +02004048static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4049{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004050 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004051 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004052 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004053
Johan Hedberg88c3df12012-02-09 14:27:38 +02004054 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4055 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004056
Johan Hedbergaee9b212012-02-18 15:07:59 +02004057 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004058 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004059
4060 *sk = cmd->sk;
4061 sock_hold(*sk);
4062
Johan Hedberga664b5b2011-02-19 12:06:02 -03004063 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004064}
4065
Johan Hedberg124f6e32012-02-09 13:50:12 +02004066static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004067{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004068 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004069 struct mgmt_cp_unpair_device *cp = cmd->param;
4070 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004071
4072 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004073 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4074 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004075
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004076 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4077
Johan Hedbergaee9b212012-02-18 15:07:59 +02004078 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004079
4080 mgmt_pending_remove(cmd);
4081}
4082
Johan Hedbergafc747a2012-01-15 18:11:07 +02004083int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004084 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004085{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004086 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004087 struct sock *sk = NULL;
4088 int err;
4089
Johan Hedberg744cf192011-11-08 20:40:14 +02004090 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004091
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004092 bacpy(&ev.addr.bdaddr, bdaddr);
4093 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4094 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004095
Johan Hedbergafc747a2012-01-15 18:11:07 +02004096 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004097 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004098
4099 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004100 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004101
Johan Hedberg124f6e32012-02-09 13:50:12 +02004102 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004103 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004104
Johan Hedberg8962ee72011-01-20 12:40:27 +02004105 return err;
4106}
4107
Johan Hedberg88c3df12012-02-09 14:27:38 +02004108int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004109 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004110{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004111 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004112 struct pending_cmd *cmd;
4113 int err;
4114
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004115 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4116 hdev);
4117
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004118 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004119 if (!cmd)
4120 return -ENOENT;
4121
Johan Hedberg88c3df12012-02-09 14:27:38 +02004122 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004123 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004124
Johan Hedberg88c3df12012-02-09 14:27:38 +02004125 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004126 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004127
Johan Hedberga664b5b2011-02-19 12:06:02 -03004128 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004129
4130 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004131}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004132
Johan Hedberg48264f02011-11-09 13:58:58 +02004133int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004134 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004135{
4136 struct mgmt_ev_connect_failed ev;
4137
Johan Hedberg4c659c32011-11-07 23:13:39 +02004138 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004139 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004140 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004141
Johan Hedberg744cf192011-11-08 20:40:14 +02004142 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004143}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004144
Johan Hedberg744cf192011-11-08 20:40:14 +02004145int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004146{
4147 struct mgmt_ev_pin_code_request ev;
4148
Johan Hedbergd8457692012-02-17 14:24:57 +02004149 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004150 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004151 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004152
Johan Hedberg744cf192011-11-08 20:40:14 +02004153 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004154 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004155}
4156
Johan Hedberg744cf192011-11-08 20:40:14 +02004157int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004158 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004159{
4160 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004161 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004162 int err;
4163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004164 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004165 if (!cmd)
4166 return -ENOENT;
4167
Johan Hedbergd8457692012-02-17 14:24:57 +02004168 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004169 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004170
Johan Hedbergaee9b212012-02-18 15:07:59 +02004171 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004172 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004173
Johan Hedberga664b5b2011-02-19 12:06:02 -03004174 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004175
4176 return err;
4177}
4178
Johan Hedberg744cf192011-11-08 20:40:14 +02004179int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004180 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004181{
4182 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004183 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004184 int err;
4185
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004186 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004187 if (!cmd)
4188 return -ENOENT;
4189
Johan Hedbergd8457692012-02-17 14:24:57 +02004190 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004191 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004192
Johan Hedbergaee9b212012-02-18 15:07:59 +02004193 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004194 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004195
Johan Hedberga664b5b2011-02-19 12:06:02 -03004196 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004197
4198 return err;
4199}
Johan Hedberga5c29682011-02-19 12:05:57 -03004200
Johan Hedberg744cf192011-11-08 20:40:14 +02004201int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004202 u8 link_type, u8 addr_type, __le32 value,
4203 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004204{
4205 struct mgmt_ev_user_confirm_request ev;
4206
Johan Hedberg744cf192011-11-08 20:40:14 +02004207 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004208
Johan Hedberg272d90d2012-02-09 15:26:12 +02004209 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004210 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004211 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004212 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004213
Johan Hedberg744cf192011-11-08 20:40:14 +02004214 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004215 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004216}
4217
Johan Hedberg272d90d2012-02-09 15:26:12 +02004218int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004219 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004220{
4221 struct mgmt_ev_user_passkey_request ev;
4222
4223 BT_DBG("%s", hdev->name);
4224
Johan Hedberg272d90d2012-02-09 15:26:12 +02004225 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004226 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004227
4228 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004229 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004230}
4231
Brian Gix0df4c182011-11-16 13:53:13 -08004232static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004233 u8 link_type, u8 addr_type, u8 status,
4234 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004235{
4236 struct pending_cmd *cmd;
4237 struct mgmt_rp_user_confirm_reply rp;
4238 int err;
4239
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004240 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004241 if (!cmd)
4242 return -ENOENT;
4243
Johan Hedberg272d90d2012-02-09 15:26:12 +02004244 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004245 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004246 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004247 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004248
Johan Hedberga664b5b2011-02-19 12:06:02 -03004249 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004250
4251 return err;
4252}
4253
Johan Hedberg744cf192011-11-08 20:40:14 +02004254int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004255 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004256{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004257 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004258 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004259}
4260
Johan Hedberg272d90d2012-02-09 15:26:12 +02004261int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004262 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004263{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004264 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004265 status,
4266 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004267}
Johan Hedberg2a611692011-02-19 12:06:00 -03004268
Brian Gix604086b2011-11-23 08:28:33 -08004269int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004270 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004271{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004272 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004273 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004274}
4275
Johan Hedberg272d90d2012-02-09 15:26:12 +02004276int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004277 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004278{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004279 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004280 status,
4281 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004282}
4283
Johan Hedberg92a25252012-09-06 18:39:26 +03004284int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4285 u8 link_type, u8 addr_type, u32 passkey,
4286 u8 entered)
4287{
4288 struct mgmt_ev_passkey_notify ev;
4289
4290 BT_DBG("%s", hdev->name);
4291
4292 bacpy(&ev.addr.bdaddr, bdaddr);
4293 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4294 ev.passkey = __cpu_to_le32(passkey);
4295 ev.entered = entered;
4296
4297 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4298}
4299
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004300int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004301 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004302{
4303 struct mgmt_ev_auth_failed ev;
4304
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004305 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004306 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004307 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004308
Johan Hedberg744cf192011-11-08 20:40:14 +02004309 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004310}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004311
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004312int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4313{
4314 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004315 bool changed = false;
4316 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004317
4318 if (status) {
4319 u8 mgmt_err = mgmt_status(status);
4320 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004321 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004322 return 0;
4323 }
4324
Johan Hedberg47990ea2012-02-22 11:58:37 +02004325 if (test_bit(HCI_AUTH, &hdev->flags)) {
4326 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4327 changed = true;
4328 } else {
4329 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4330 changed = true;
4331 }
4332
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004333 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004334 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004335
Johan Hedberg47990ea2012-02-22 11:58:37 +02004336 if (changed)
4337 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004338
4339 if (match.sk)
4340 sock_put(match.sk);
4341
4342 return err;
4343}
4344
Johan Hedberg890ea892013-03-15 17:06:52 -05004345static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004346{
Johan Hedberg890ea892013-03-15 17:06:52 -05004347 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004348 struct hci_cp_write_eir cp;
4349
Johan Hedberg976eb202012-10-24 21:12:01 +03004350 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004351 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004352
Johan Hedbergc80da272012-02-22 15:38:48 +02004353 memset(hdev->eir, 0, sizeof(hdev->eir));
4354
Johan Hedbergcacaf522012-02-21 00:52:42 +02004355 memset(&cp, 0, sizeof(cp));
4356
Johan Hedberg890ea892013-03-15 17:06:52 -05004357 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004358}
4359
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004360int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004361{
4362 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004363 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004364 bool changed = false;
4365 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004366
4367 if (status) {
4368 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004369
4370 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004371 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004372 err = new_settings(hdev, NULL);
4373
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004374 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4375 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004376
4377 return err;
4378 }
4379
4380 if (enable) {
4381 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4382 changed = true;
4383 } else {
4384 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4385 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004386 }
4387
4388 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4389
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004390 if (changed)
4391 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004392
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004393 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004394 sock_put(match.sk);
4395
Johan Hedberg890ea892013-03-15 17:06:52 -05004396 hci_req_init(&req, hdev);
4397
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004398 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004399 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004400 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004401 clear_eir(&req);
4402
4403 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004404
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004405 return err;
4406}
4407
Johan Hedberg92da6092013-03-15 17:06:55 -05004408static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004409{
4410 struct cmd_lookup *match = data;
4411
Johan Hedberg90e70452012-02-23 23:09:40 +02004412 if (match->sk == NULL) {
4413 match->sk = cmd->sk;
4414 sock_hold(match->sk);
4415 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004416}
4417
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004418int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004419 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004420{
Johan Hedberg90e70452012-02-23 23:09:40 +02004421 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4422 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004423
Johan Hedberg92da6092013-03-15 17:06:55 -05004424 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4425 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4426 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004427
4428 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004429 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4430 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004431
4432 if (match.sk)
4433 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004434
4435 return err;
4436}
4437
Johan Hedberg744cf192011-11-08 20:40:14 +02004438int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004439{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004440 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004441 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004442
Johan Hedberg13928972013-03-15 17:07:00 -05004443 if (status)
4444 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004445
4446 memset(&ev, 0, sizeof(ev));
4447 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004448 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004449
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004450 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004451 if (!cmd) {
4452 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004453
Johan Hedberg13928972013-03-15 17:07:00 -05004454 /* If this is a HCI command related to powering on the
4455 * HCI dev don't send any mgmt signals.
4456 */
4457 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4458 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004459 }
4460
Johan Hedberg13928972013-03-15 17:07:00 -05004461 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4462 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004463}
Szymon Jancc35938b2011-03-22 13:12:21 +01004464
Johan Hedberg744cf192011-11-08 20:40:14 +02004465int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004466 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004467{
4468 struct pending_cmd *cmd;
4469 int err;
4470
Johan Hedberg744cf192011-11-08 20:40:14 +02004471 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004472
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004473 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004474 if (!cmd)
4475 return -ENOENT;
4476
4477 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004478 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4479 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004480 } else {
4481 struct mgmt_rp_read_local_oob_data rp;
4482
4483 memcpy(rp.hash, hash, sizeof(rp.hash));
4484 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4485
Johan Hedberg744cf192011-11-08 20:40:14 +02004486 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004487 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4488 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004489 }
4490
4491 mgmt_pending_remove(cmd);
4492
4493 return err;
4494}
Johan Hedberge17acd42011-03-30 23:57:16 +03004495
Johan Hedberg48264f02011-11-09 13:58:58 +02004496int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004497 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4498 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004499{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004500 char buf[512];
4501 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004502 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004503
Andre Guedes12602d02013-04-30 15:29:40 -03004504 if (!hci_discovery_active(hdev))
4505 return -EPERM;
4506
Johan Hedberg1dc06092012-01-15 21:01:23 +02004507 /* Leave 5 bytes for a potential CoD field */
4508 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004509 return -EINVAL;
4510
Johan Hedberg1dc06092012-01-15 21:01:23 +02004511 memset(buf, 0, sizeof(buf));
4512
Johan Hedberge319d2e2012-01-15 19:51:59 +02004513 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004514 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004515 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004516 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304517 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004518 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304519 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004520
Johan Hedberg1dc06092012-01-15 21:01:23 +02004521 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004522 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004523
Johan Hedberg1dc06092012-01-15 21:01:23 +02004524 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4525 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004526 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004527
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004528 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004529 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004530
Johan Hedberge319d2e2012-01-15 19:51:59 +02004531 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004532}
Johan Hedberga88a9652011-03-30 13:18:12 +03004533
Johan Hedbergb644ba32012-01-17 21:48:47 +02004534int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004535 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004536{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004537 struct mgmt_ev_device_found *ev;
4538 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4539 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004540
Johan Hedbergb644ba32012-01-17 21:48:47 +02004541 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004542
Johan Hedbergb644ba32012-01-17 21:48:47 +02004543 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004544
Johan Hedbergb644ba32012-01-17 21:48:47 +02004545 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004546 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004547 ev->rssi = rssi;
4548
4549 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004550 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004551
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004552 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004553
Johan Hedberg053c7e02012-02-04 00:06:00 +02004554 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004555 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004556}
Johan Hedberg314b2382011-04-27 10:29:57 -04004557
Johan Hedberg744cf192011-11-08 20:40:14 +02004558int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004559{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004560 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004561 struct pending_cmd *cmd;
4562
Andre Guedes343fb142011-11-22 17:14:19 -03004563 BT_DBG("%s discovering %u", hdev->name, discovering);
4564
Johan Hedberg164a6e72011-11-01 17:06:44 +02004565 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004566 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004567 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004568 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004569
4570 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004571 u8 type = hdev->discovery.type;
4572
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004573 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4574 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004575 mgmt_pending_remove(cmd);
4576 }
4577
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004578 memset(&ev, 0, sizeof(ev));
4579 ev.type = hdev->discovery.type;
4580 ev.discovering = discovering;
4581
4582 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004583}
Antti Julku5e762442011-08-25 16:48:02 +03004584
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004585int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004586{
4587 struct pending_cmd *cmd;
4588 struct mgmt_ev_device_blocked ev;
4589
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004590 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004591
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004592 bacpy(&ev.addr.bdaddr, bdaddr);
4593 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004594
Johan Hedberg744cf192011-11-08 20:40:14 +02004595 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004596 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004597}
4598
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004599int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004600{
4601 struct pending_cmd *cmd;
4602 struct mgmt_ev_device_unblocked ev;
4603
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004604 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004605
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004606 bacpy(&ev.addr.bdaddr, bdaddr);
4607 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004608
Johan Hedberg744cf192011-11-08 20:40:14 +02004609 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004611}