blob: 381faf6001951df08859af5738bfa9b1d63a4266 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg2da9c552012-02-17 14:39:28 +020035#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070036#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020037
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070076 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030077 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030078 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070079 MGMT_OP_SET_STATIC_ADDRESS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020080};
81
82static const u16 mgmt_events[] = {
83 MGMT_EV_CONTROLLER_ERROR,
84 MGMT_EV_INDEX_ADDED,
85 MGMT_EV_INDEX_REMOVED,
86 MGMT_EV_NEW_SETTINGS,
87 MGMT_EV_CLASS_OF_DEV_CHANGED,
88 MGMT_EV_LOCAL_NAME_CHANGED,
89 MGMT_EV_NEW_LINK_KEY,
90 MGMT_EV_NEW_LONG_TERM_KEY,
91 MGMT_EV_DEVICE_CONNECTED,
92 MGMT_EV_DEVICE_DISCONNECTED,
93 MGMT_EV_CONNECT_FAILED,
94 MGMT_EV_PIN_CODE_REQUEST,
95 MGMT_EV_USER_CONFIRM_REQUEST,
96 MGMT_EV_USER_PASSKEY_REQUEST,
97 MGMT_EV_AUTH_FAILED,
98 MGMT_EV_DEVICE_FOUND,
99 MGMT_EV_DISCOVERING,
100 MGMT_EV_DEVICE_BLOCKED,
101 MGMT_EV_DEVICE_UNBLOCKED,
102 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300103 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200104};
105
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800106#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200107
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200108#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
109 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
110
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200111struct pending_cmd {
112 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200113 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100115 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300117 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118};
119
Johan Hedbergca69b792011-11-11 18:10:00 +0200120/* HCI to MGMT error code conversion table */
121static u8 mgmt_status_table[] = {
122 MGMT_STATUS_SUCCESS,
123 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
124 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
125 MGMT_STATUS_FAILED, /* Hardware Failure */
126 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
127 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
128 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
129 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
130 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
132 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
133 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
134 MGMT_STATUS_BUSY, /* Command Disallowed */
135 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
136 MGMT_STATUS_REJECTED, /* Rejected Security */
137 MGMT_STATUS_REJECTED, /* Rejected Personal */
138 MGMT_STATUS_TIMEOUT, /* Host Timeout */
139 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
140 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
141 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
142 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
143 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
144 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
145 MGMT_STATUS_BUSY, /* Repeated Attempts */
146 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
147 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
148 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
149 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
150 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
151 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
153 MGMT_STATUS_FAILED, /* Unspecified Error */
154 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
155 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
156 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
157 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
158 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
159 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
160 MGMT_STATUS_FAILED, /* Unit Link Key Used */
161 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
162 MGMT_STATUS_TIMEOUT, /* Instant Passed */
163 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
164 MGMT_STATUS_FAILED, /* Transaction Collision */
165 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
166 MGMT_STATUS_REJECTED, /* QoS Rejected */
167 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
168 MGMT_STATUS_REJECTED, /* Insufficient Security */
169 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
170 MGMT_STATUS_BUSY, /* Role Switch Pending */
171 MGMT_STATUS_FAILED, /* Slot Violation */
172 MGMT_STATUS_FAILED, /* Role Switch Failed */
173 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
174 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
175 MGMT_STATUS_BUSY, /* Host Busy Pairing */
176 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
177 MGMT_STATUS_BUSY, /* Controller Busy */
178 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
179 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
180 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
181 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
182 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
183};
184
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300185bool mgmt_valid_hdev(struct hci_dev *hdev)
186{
187 return hdev->dev_type == HCI_BREDR;
188}
189
Johan Hedbergca69b792011-11-11 18:10:00 +0200190static u8 mgmt_status(u8 hci_status)
191{
192 if (hci_status < ARRAY_SIZE(mgmt_status_table))
193 return mgmt_status_table[hci_status];
194
195 return MGMT_STATUS_FAILED;
196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan 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 Hedbergf3d3444a2013-10-05 12:01:04 +0200428 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300429 settings |= MGMT_SETTING_ADVERTISING;
430
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200431 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200432}
433
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300434#define PNP_INFO_SVCLASS_ID 0x1200
435
Johan Hedberg213202e2013-01-27 00:31:33 +0200436static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
437{
438 u8 *ptr = data, *uuids_start = NULL;
439 struct bt_uuid *uuid;
440
441 if (len < 4)
442 return ptr;
443
444 list_for_each_entry(uuid, &hdev->uuids, list) {
445 u16 uuid16;
446
447 if (uuid->size != 16)
448 continue;
449
450 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
451 if (uuid16 < 0x1100)
452 continue;
453
454 if (uuid16 == PNP_INFO_SVCLASS_ID)
455 continue;
456
457 if (!uuids_start) {
458 uuids_start = ptr;
459 uuids_start[0] = 1;
460 uuids_start[1] = EIR_UUID16_ALL;
461 ptr += 2;
462 }
463
464 /* Stop if not enough space to put next UUID */
465 if ((ptr - data) + sizeof(u16) > len) {
466 uuids_start[1] = EIR_UUID16_SOME;
467 break;
468 }
469
470 *ptr++ = (uuid16 & 0x00ff);
471 *ptr++ = (uuid16 & 0xff00) >> 8;
472 uuids_start[0] += sizeof(uuid16);
473 }
474
475 return ptr;
476}
477
Johan Hedbergcdf19632013-01-27 00:31:34 +0200478static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
479{
480 u8 *ptr = data, *uuids_start = NULL;
481 struct bt_uuid *uuid;
482
483 if (len < 6)
484 return ptr;
485
486 list_for_each_entry(uuid, &hdev->uuids, list) {
487 if (uuid->size != 32)
488 continue;
489
490 if (!uuids_start) {
491 uuids_start = ptr;
492 uuids_start[0] = 1;
493 uuids_start[1] = EIR_UUID32_ALL;
494 ptr += 2;
495 }
496
497 /* Stop if not enough space to put next UUID */
498 if ((ptr - data) + sizeof(u32) > len) {
499 uuids_start[1] = EIR_UUID32_SOME;
500 break;
501 }
502
503 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
504 ptr += sizeof(u32);
505 uuids_start[0] += sizeof(u32);
506 }
507
508 return ptr;
509}
510
Johan Hedbergc00d5752013-01-27 00:31:35 +0200511static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
512{
513 u8 *ptr = data, *uuids_start = NULL;
514 struct bt_uuid *uuid;
515
516 if (len < 18)
517 return ptr;
518
519 list_for_each_entry(uuid, &hdev->uuids, list) {
520 if (uuid->size != 128)
521 continue;
522
523 if (!uuids_start) {
524 uuids_start = ptr;
525 uuids_start[0] = 1;
526 uuids_start[1] = EIR_UUID128_ALL;
527 ptr += 2;
528 }
529
530 /* Stop if not enough space to put next UUID */
531 if ((ptr - data) + 16 > len) {
532 uuids_start[1] = EIR_UUID128_SOME;
533 break;
534 }
535
536 memcpy(ptr, uuid->uuid, 16);
537 ptr += 16;
538 uuids_start[0] += 16;
539 }
540
541 return ptr;
542}
543
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300544static void create_eir(struct hci_dev *hdev, u8 *data)
545{
546 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547 size_t name_len;
548
549 name_len = strlen(hdev->dev_name);
550
551 if (name_len > 0) {
552 /* EIR Data type */
553 if (name_len > 48) {
554 name_len = 48;
555 ptr[1] = EIR_NAME_SHORT;
556 } else
557 ptr[1] = EIR_NAME_COMPLETE;
558
559 /* EIR Data length */
560 ptr[0] = name_len + 1;
561
562 memcpy(ptr + 2, hdev->dev_name, name_len);
563
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 ptr += (name_len + 2);
565 }
566
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100567 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700568 ptr[0] = 2;
569 ptr[1] = EIR_TX_POWER;
570 ptr[2] = (u8) hdev->inq_tx_power;
571
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700572 ptr += 3;
573 }
574
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700575 if (hdev->devid_source > 0) {
576 ptr[0] = 9;
577 ptr[1] = EIR_DEVICE_ID;
578
579 put_unaligned_le16(hdev->devid_source, ptr + 2);
580 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
581 put_unaligned_le16(hdev->devid_product, ptr + 6);
582 put_unaligned_le16(hdev->devid_version, ptr + 8);
583
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700584 ptr += 10;
585 }
586
Johan Hedberg213202e2013-01-27 00:31:33 +0200587 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200588 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200589 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300590}
591
Johan Hedberg890ea892013-03-15 17:06:52 -0500592static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300593{
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595 struct hci_cp_write_eir cp;
596
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200597 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500598 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200599
Johan Hedberg976eb202012-10-24 21:12:01 +0300600 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500601 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300602
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200603 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500604 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300605
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200606 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500607 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608
609 memset(&cp, 0, sizeof(cp));
610
611 create_eir(hdev, cp.data);
612
613 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500614 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300615
616 memcpy(hdev->eir, cp.data, sizeof(cp.data));
617
Johan Hedberg890ea892013-03-15 17:06:52 -0500618 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300619}
620
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621static u8 get_service_classes(struct hci_dev *hdev)
622{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300623 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624 u8 val = 0;
625
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300626 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628
629 return val;
630}
631
Johan Hedberg890ea892013-03-15 17:06:52 -0500632static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200633{
Johan Hedberg890ea892013-03-15 17:06:52 -0500634 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200635 u8 cod[3];
636
637 BT_DBG("%s", hdev->name);
638
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200639 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500640 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200641
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200642 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500643 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200644
645 cod[0] = hdev->minor_class;
646 cod[1] = hdev->major_class;
647 cod[2] = get_service_classes(hdev);
648
649 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500650 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200651
Johan Hedberg890ea892013-03-15 17:06:52 -0500652 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200653}
654
Johan Hedberg7d785252011-12-15 00:47:39 +0200655static void service_cache_off(struct work_struct *work)
656{
657 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300658 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500659 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200660
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200661 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200662 return;
663
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 hci_req_init(&req, hdev);
665
Johan Hedberg7d785252011-12-15 00:47:39 +0200666 hci_dev_lock(hdev);
667
Johan Hedberg890ea892013-03-15 17:06:52 -0500668 update_eir(&req);
669 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200670
671 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500672
673 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200674}
675
Johan Hedberg6a919082012-02-28 06:17:26 +0200676static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200677{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200678 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200679 return;
680
Johan Hedberg4f87da82012-03-02 19:55:56 +0200681 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200682
Johan Hedberg4f87da82012-03-02 19:55:56 +0200683 /* Non-mgmt controlled devices get this bit set
684 * implicitly so that pairing works for them, however
685 * for mgmt we require user-space to explicitly enable
686 * it
687 */
688 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200689}
690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200691static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200693{
694 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200696 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200697
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300698 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200699
Johan Hedberg03811012010-12-08 00:21:06 +0200700 memset(&rp, 0, sizeof(rp));
701
Johan Hedberg03811012010-12-08 00:21:06 +0200702 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200703
704 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200705 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200706
707 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
708 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
709
710 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200711
712 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200713 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300715 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200716
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200717 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300718 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200719}
720
721static void mgmt_pending_free(struct pending_cmd *cmd)
722{
723 sock_put(cmd->sk);
724 kfree(cmd->param);
725 kfree(cmd);
726}
727
728static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300729 struct hci_dev *hdev, void *data,
730 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200731{
732 struct pending_cmd *cmd;
733
Andre Guedes12b94562012-06-07 19:05:45 -0300734 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200735 if (!cmd)
736 return NULL;
737
738 cmd->opcode = opcode;
739 cmd->index = hdev->id;
740
Andre Guedes12b94562012-06-07 19:05:45 -0300741 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 if (!cmd->param) {
743 kfree(cmd);
744 return NULL;
745 }
746
747 if (data)
748 memcpy(cmd->param, data, len);
749
750 cmd->sk = sk;
751 sock_hold(sk);
752
753 list_add(&cmd->list, &hdev->mgmt_pending);
754
755 return cmd;
756}
757
758static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300759 void (*cb)(struct pending_cmd *cmd,
760 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300761 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200762{
Andre Guedesa3d09352013-02-01 11:21:30 -0300763 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Andre Guedesa3d09352013-02-01 11:21:30 -0300765 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200766 if (opcode > 0 && cmd->opcode != opcode)
767 continue;
768
769 cb(cmd, data);
770 }
771}
772
773static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
774{
775 struct pending_cmd *cmd;
776
777 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
778 if (cmd->opcode == opcode)
779 return cmd;
780 }
781
782 return NULL;
783}
784
785static void mgmt_pending_remove(struct pending_cmd *cmd)
786{
787 list_del(&cmd->list);
788 mgmt_pending_free(cmd);
789}
790
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200792{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200793 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200794
Johan 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 Hedbergd2f5a192013-10-05 12:01:05 +0200893int mgmt_new_settings(struct hci_dev *hdev)
894{
895 return new_settings(hdev, NULL);
896}
897
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300898struct cmd_lookup {
899 struct sock *sk;
900 struct hci_dev *hdev;
901 u8 mgmt_status;
902};
903
904static void settings_rsp(struct pending_cmd *cmd, void *data)
905{
906 struct cmd_lookup *match = data;
907
908 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
909
910 list_del(&cmd->list);
911
912 if (match->sk == NULL) {
913 match->sk = cmd->sk;
914 sock_hold(match->sk);
915 }
916
917 mgmt_pending_free(cmd);
918}
919
920static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
921{
922 u8 *status = data;
923
924 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
925 mgmt_pending_remove(cmd);
926}
927
Johan Hedberge6fe7982013-10-02 15:45:22 +0300928static u8 mgmt_bredr_support(struct hci_dev *hdev)
929{
930 if (!lmp_bredr_capable(hdev))
931 return MGMT_STATUS_NOT_SUPPORTED;
932 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
933 return MGMT_STATUS_REJECTED;
934 else
935 return MGMT_STATUS_SUCCESS;
936}
937
938static u8 mgmt_le_support(struct hci_dev *hdev)
939{
940 if (!lmp_le_capable(hdev))
941 return MGMT_STATUS_NOT_SUPPORTED;
942 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
943 return MGMT_STATUS_REJECTED;
944 else
945 return MGMT_STATUS_SUCCESS;
946}
947
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200948static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300949 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200950{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300951 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200952 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200953 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300954 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200955 int err;
956
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200957 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200958
Johan Hedberge6fe7982013-10-02 15:45:22 +0300959 status = mgmt_bredr_support(hdev);
960 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300961 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300962 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300963
Johan Hedberga7e80f22013-01-09 16:05:19 +0200964 if (cp->val != 0x00 && cp->val != 0x01)
965 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
966 MGMT_STATUS_INVALID_PARAMS);
967
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700968 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100969 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200970 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300971 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200972
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300973 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200976 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300977 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200978 goto failed;
979 }
980
981 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300982 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200983 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300984 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200985 goto failed;
986 }
987
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200988 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200989 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300990 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200991 goto failed;
992 }
993
994 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200995 bool changed = false;
996
997 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
998 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
999 changed = true;
1000 }
1001
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001002 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001003 if (err < 0)
1004 goto failed;
1005
1006 if (changed)
1007 err = new_settings(hdev, sk);
1008
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001009 goto failed;
1010 }
1011
1012 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001013 if (hdev->discov_timeout > 0) {
1014 cancel_delayed_work(&hdev->discov_off);
1015 hdev->discov_timeout = 0;
1016 }
1017
1018 if (cp->val && timeout > 0) {
1019 hdev->discov_timeout = timeout;
1020 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1021 msecs_to_jiffies(hdev->discov_timeout * 1000));
1022 }
1023
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001024 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001025 goto failed;
1026 }
1027
1028 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1029 if (!cmd) {
1030 err = -ENOMEM;
1031 goto failed;
1032 }
1033
1034 scan = SCAN_PAGE;
1035
1036 if (cp->val)
1037 scan |= SCAN_INQUIRY;
1038 else
1039 cancel_delayed_work(&hdev->discov_off);
1040
1041 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1042 if (err < 0)
1043 mgmt_pending_remove(cmd);
1044
Johan Hedberg03811012010-12-08 00:21:06 +02001045 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001046 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001047
1048failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001049 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001050 return err;
1051}
1052
Johan Hedberg406d7802013-03-15 17:07:09 -05001053static void write_fast_connectable(struct hci_request *req, bool enable)
1054{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001055 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001056 struct hci_cp_write_page_scan_activity acp;
1057 u8 type;
1058
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001059 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1060 return;
1061
Johan Hedberg406d7802013-03-15 17:07:09 -05001062 if (enable) {
1063 type = PAGE_SCAN_TYPE_INTERLACED;
1064
1065 /* 160 msec page scan interval */
1066 acp.interval = __constant_cpu_to_le16(0x0100);
1067 } else {
1068 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1069
1070 /* default 1.28 sec page scan */
1071 acp.interval = __constant_cpu_to_le16(0x0800);
1072 }
1073
1074 acp.window = __constant_cpu_to_le16(0x0012);
1075
Johan Hedbergbd98b992013-03-15 17:07:13 -05001076 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1077 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1078 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1079 sizeof(acp), &acp);
1080
1081 if (hdev->page_scan_type != type)
1082 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001083}
1084
Johan Hedberg2b76f452013-03-15 17:07:04 -05001085static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1086{
1087 struct pending_cmd *cmd;
1088
1089 BT_DBG("status 0x%02x", status);
1090
1091 hci_dev_lock(hdev);
1092
1093 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1094 if (!cmd)
1095 goto unlock;
1096
1097 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1098
1099 mgmt_pending_remove(cmd);
1100
1101unlock:
1102 hci_dev_unlock(hdev);
1103}
1104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001105static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001106 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001107{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001108 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001109 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001110 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001111 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001112 int err;
1113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001114 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001115
Johan Hedberge6fe7982013-10-02 15:45:22 +03001116 status = mgmt_bredr_support(hdev);
1117 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001118 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001119 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001120
Johan Hedberga7e80f22013-01-09 16:05:19 +02001121 if (cp->val != 0x00 && cp->val != 0x01)
1122 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1123 MGMT_STATUS_INVALID_PARAMS);
1124
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001125 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001126
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001127 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001128 bool changed = false;
1129
1130 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1131 changed = true;
1132
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001133 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001134 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001135 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001136 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1137 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1138 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001139
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001140 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001141 if (err < 0)
1142 goto failed;
1143
1144 if (changed)
1145 err = new_settings(hdev, sk);
1146
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001147 goto failed;
1148 }
1149
1150 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001151 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001152 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001153 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001154 goto failed;
1155 }
1156
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001157 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001158 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001159 goto failed;
1160 }
1161
1162 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1163 if (!cmd) {
1164 err = -ENOMEM;
1165 goto failed;
1166 }
1167
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001168 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001169 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001170 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001171 scan = 0;
1172
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001173 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001174 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001175 cancel_delayed_work(&hdev->discov_off);
1176 }
1177
Johan Hedberg2b76f452013-03-15 17:07:04 -05001178 hci_req_init(&req, hdev);
1179
1180 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1181
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001182 /* If we're going from non-connectable to connectable or
1183 * vice-versa when fast connectable is enabled ensure that fast
1184 * connectable gets disabled. write_fast_connectable won't do
1185 * anything if the page scan parameters are already what they
1186 * should be.
1187 */
1188 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001189 write_fast_connectable(&req, false);
1190
Johan Hedberg2b76f452013-03-15 17:07:04 -05001191 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192 if (err < 0)
1193 mgmt_pending_remove(cmd);
1194
1195failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001196 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001197 return err;
1198}
1199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001201 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001202{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001203 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001204 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001205
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001206 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207
Johan Hedberga7e80f22013-01-09 16:05:19 +02001208 if (cp->val != 0x00 && cp->val != 0x01)
1209 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1210 MGMT_STATUS_INVALID_PARAMS);
1211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001212 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
1214 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001215 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001216 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001217 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001218
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001219 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001220 if (err < 0)
1221 goto failed;
1222
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001223 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001224
1225failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001226 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001227 return err;
1228}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001229
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001230static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1231 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001232{
1233 struct mgmt_mode *cp = data;
1234 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001235 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001236 int err;
1237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001238 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001239
Johan Hedberge6fe7982013-10-02 15:45:22 +03001240 status = mgmt_bredr_support(hdev);
1241 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001242 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001243 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001244
Johan Hedberga7e80f22013-01-09 16:05:19 +02001245 if (cp->val != 0x00 && cp->val != 0x01)
1246 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1247 MGMT_STATUS_INVALID_PARAMS);
1248
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001249 hci_dev_lock(hdev);
1250
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001251 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001252 bool changed = false;
1253
1254 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001255 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001256 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1257 changed = true;
1258 }
1259
1260 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1261 if (err < 0)
1262 goto failed;
1263
1264 if (changed)
1265 err = new_settings(hdev, sk);
1266
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001267 goto failed;
1268 }
1269
1270 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001271 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001272 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001273 goto failed;
1274 }
1275
1276 val = !!cp->val;
1277
1278 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1279 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1280 goto failed;
1281 }
1282
1283 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1284 if (!cmd) {
1285 err = -ENOMEM;
1286 goto failed;
1287 }
1288
1289 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1290 if (err < 0) {
1291 mgmt_pending_remove(cmd);
1292 goto failed;
1293 }
1294
1295failed:
1296 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001297 return err;
1298}
1299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001300static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001301{
1302 struct mgmt_mode *cp = data;
1303 struct pending_cmd *cmd;
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001304 u8 val, status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001305 int err;
1306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001307 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001308
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001309 status = mgmt_bredr_support(hdev);
1310 if (status)
1311 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1312
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001313 if (!lmp_ssp_capable(hdev))
1314 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1315 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001316
Johan Hedberga7e80f22013-01-09 16:05:19 +02001317 if (cp->val != 0x00 && cp->val != 0x01)
1318 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1319 MGMT_STATUS_INVALID_PARAMS);
1320
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001321 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001322
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001323 val = !!cp->val;
1324
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001325 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001326 bool changed = false;
1327
1328 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1329 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1330 changed = true;
1331 }
1332
1333 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1334 if (err < 0)
1335 goto failed;
1336
1337 if (changed)
1338 err = new_settings(hdev, sk);
1339
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001340 goto failed;
1341 }
1342
1343 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001344 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1345 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001346 goto failed;
1347 }
1348
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001349 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1350 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1351 goto failed;
1352 }
1353
1354 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1355 if (!cmd) {
1356 err = -ENOMEM;
1357 goto failed;
1358 }
1359
1360 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1361 if (err < 0) {
1362 mgmt_pending_remove(cmd);
1363 goto failed;
1364 }
1365
1366failed:
1367 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001368 return err;
1369}
1370
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001371static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001372{
1373 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001374 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001375 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001376 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001377
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001378 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001379
Johan Hedberge6fe7982013-10-02 15:45:22 +03001380 status = mgmt_bredr_support(hdev);
1381 if (status)
1382 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001383
Johan Hedberga7e80f22013-01-09 16:05:19 +02001384 if (cp->val != 0x00 && cp->val != 0x01)
1385 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1386 MGMT_STATUS_INVALID_PARAMS);
1387
Marcel Holtmannee392692013-10-01 22:59:23 -07001388 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001389
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001390 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001391 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001392 } else {
1393 if (hdev_is_powered(hdev)) {
1394 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1395 MGMT_STATUS_REJECTED);
1396 goto unlock;
1397 }
1398
Marcel Holtmannee392692013-10-01 22:59:23 -07001399 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001400 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001401
1402 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1403 if (err < 0)
1404 goto unlock;
1405
1406 if (changed)
1407 err = new_settings(hdev, sk);
1408
1409unlock:
1410 hci_dev_unlock(hdev);
1411 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001412}
1413
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001414static void enable_advertising(struct hci_request *req)
1415{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001416 struct hci_dev *hdev = req->hdev;
1417 struct hci_cp_le_set_adv_param cp;
1418 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001419
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001420 memset(&cp, 0, sizeof(cp));
1421 cp.min_interval = __constant_cpu_to_le16(0x0800);
1422 cp.max_interval = __constant_cpu_to_le16(0x0800);
1423 cp.type = LE_ADV_IND;
1424 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1425 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1426 else
1427 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1428 cp.channel_map = 0x07;
1429
1430 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1431
1432 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001433}
1434
1435static void disable_advertising(struct hci_request *req)
1436{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001437 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001438
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001439 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001440}
1441
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001442static void le_enable_complete(struct hci_dev *hdev, u8 status)
1443{
1444 struct cmd_lookup match = { NULL, hdev };
1445
1446 if (status) {
1447 u8 mgmt_err = mgmt_status(status);
1448
1449 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1450 &mgmt_err);
1451 return;
1452 }
1453
1454 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1455
1456 new_settings(hdev, match.sk);
1457
1458 if (match.sk)
1459 sock_put(match.sk);
1460}
1461
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001462static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001463{
1464 struct mgmt_mode *cp = data;
1465 struct hci_cp_write_le_host_supported hci_cp;
1466 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001467 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001468 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001469 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001471 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001472
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001473 if (!lmp_le_capable(hdev))
1474 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1475 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001476
Johan Hedberga7e80f22013-01-09 16:05:19 +02001477 if (cp->val != 0x00 && cp->val != 0x01)
1478 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1479 MGMT_STATUS_INVALID_PARAMS);
1480
Johan Hedbergc73eee92013-04-19 18:35:21 +03001481 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001482 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001483 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1484 MGMT_STATUS_REJECTED);
1485
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001486 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001487
1488 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001489 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001490
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001491 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001492 bool changed = false;
1493
1494 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1495 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1496 changed = true;
1497 }
1498
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001499 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1500 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001501 changed = true;
1502 }
1503
Johan Hedberg06199cf2012-02-22 16:37:11 +02001504 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1505 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001506 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001507
1508 if (changed)
1509 err = new_settings(hdev, sk);
1510
Johan Hedberg1de028c2012-02-29 19:55:35 -08001511 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001512 }
1513
Johan Hedberg4375f102013-09-25 13:26:10 +03001514 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1515 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001516 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001517 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001518 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001519 }
1520
1521 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1522 if (!cmd) {
1523 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001524 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001525 }
1526
1527 memset(&hci_cp, 0, sizeof(hci_cp));
1528
1529 if (val) {
1530 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001531 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001532 }
1533
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001534 hci_req_init(&req, hdev);
1535
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001536 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1537 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001538
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001539 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1540 &hci_cp);
1541
1542 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301543 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001544 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001545
Johan Hedberg1de028c2012-02-29 19:55:35 -08001546unlock:
1547 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001548 return err;
1549}
1550
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001551/* This is a helper function to test for pending mgmt commands that can
1552 * cause CoD or EIR HCI commands. We can only allow one such pending
1553 * mgmt command at a time since otherwise we cannot easily track what
1554 * the current values are, will be, and based on that calculate if a new
1555 * HCI command needs to be sent and if yes with what value.
1556 */
1557static bool pending_eir_or_class(struct hci_dev *hdev)
1558{
1559 struct pending_cmd *cmd;
1560
1561 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1562 switch (cmd->opcode) {
1563 case MGMT_OP_ADD_UUID:
1564 case MGMT_OP_REMOVE_UUID:
1565 case MGMT_OP_SET_DEV_CLASS:
1566 case MGMT_OP_SET_POWERED:
1567 return true;
1568 }
1569 }
1570
1571 return false;
1572}
1573
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001574static const u8 bluetooth_base_uuid[] = {
1575 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1576 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1577};
1578
1579static u8 get_uuid_size(const u8 *uuid)
1580{
1581 u32 val;
1582
1583 if (memcmp(uuid, bluetooth_base_uuid, 12))
1584 return 128;
1585
1586 val = get_unaligned_le32(&uuid[12]);
1587 if (val > 0xffff)
1588 return 32;
1589
1590 return 16;
1591}
1592
Johan Hedberg92da6092013-03-15 17:06:55 -05001593static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1594{
1595 struct pending_cmd *cmd;
1596
1597 hci_dev_lock(hdev);
1598
1599 cmd = mgmt_pending_find(mgmt_op, hdev);
1600 if (!cmd)
1601 goto unlock;
1602
1603 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1604 hdev->dev_class, 3);
1605
1606 mgmt_pending_remove(cmd);
1607
1608unlock:
1609 hci_dev_unlock(hdev);
1610}
1611
1612static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1613{
1614 BT_DBG("status 0x%02x", status);
1615
1616 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1617}
1618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001619static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001620{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001621 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001622 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001623 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001624 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625 int err;
1626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001627 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001629 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001631 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001632 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001633 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001634 goto failed;
1635 }
1636
Andre Guedes92c4c202012-06-07 19:05:44 -03001637 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001638 if (!uuid) {
1639 err = -ENOMEM;
1640 goto failed;
1641 }
1642
1643 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001644 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001645 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001646
Johan Hedbergde66aa62013-01-27 00:31:27 +02001647 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001648
Johan Hedberg890ea892013-03-15 17:06:52 -05001649 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001650
Johan Hedberg890ea892013-03-15 17:06:52 -05001651 update_class(&req);
1652 update_eir(&req);
1653
Johan Hedberg92da6092013-03-15 17:06:55 -05001654 err = hci_req_run(&req, add_uuid_complete);
1655 if (err < 0) {
1656 if (err != -ENODATA)
1657 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001658
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001659 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001660 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001661 goto failed;
1662 }
1663
1664 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001665 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001666 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001667 goto failed;
1668 }
1669
1670 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001671
1672failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001673 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001674 return err;
1675}
1676
Johan Hedberg24b78d02012-02-23 23:24:30 +02001677static bool enable_service_cache(struct hci_dev *hdev)
1678{
1679 if (!hdev_is_powered(hdev))
1680 return false;
1681
1682 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001683 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1684 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001685 return true;
1686 }
1687
1688 return false;
1689}
1690
Johan Hedberg92da6092013-03-15 17:06:55 -05001691static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1692{
1693 BT_DBG("status 0x%02x", status);
1694
1695 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1696}
1697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001698static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001699 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001700{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001701 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001702 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001703 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001704 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 -05001705 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001706 int err, found;
1707
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001708 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001709
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001710 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001711
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001712 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001713 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001715 goto unlock;
1716 }
1717
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001718 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1719 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001720
Johan Hedberg24b78d02012-02-23 23:24:30 +02001721 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001722 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001723 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001724 goto unlock;
1725 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001726
Johan Hedberg9246a862012-02-23 21:33:16 +02001727 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001728 }
1729
1730 found = 0;
1731
Johan Hedberg056341c2013-01-27 00:31:30 +02001732 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001733 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1734 continue;
1735
1736 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001737 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001738 found++;
1739 }
1740
1741 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001742 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001743 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001744 goto unlock;
1745 }
1746
Johan Hedberg9246a862012-02-23 21:33:16 +02001747update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001748 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001749
Johan Hedberg890ea892013-03-15 17:06:52 -05001750 update_class(&req);
1751 update_eir(&req);
1752
Johan Hedberg92da6092013-03-15 17:06:55 -05001753 err = hci_req_run(&req, remove_uuid_complete);
1754 if (err < 0) {
1755 if (err != -ENODATA)
1756 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001757
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001758 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001759 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001760 goto unlock;
1761 }
1762
1763 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001764 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001765 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001766 goto unlock;
1767 }
1768
1769 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001770
1771unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001772 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001773 return err;
1774}
1775
Johan Hedberg92da6092013-03-15 17:06:55 -05001776static void set_class_complete(struct hci_dev *hdev, u8 status)
1777{
1778 BT_DBG("status 0x%02x", status);
1779
1780 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1781}
1782
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001783static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001784 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001785{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001786 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001787 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001788 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001789 int err;
1790
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001791 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001792
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001793 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001794 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1795 MGMT_STATUS_NOT_SUPPORTED);
1796
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001797 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001798
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001799 if (pending_eir_or_class(hdev)) {
1800 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1801 MGMT_STATUS_BUSY);
1802 goto unlock;
1803 }
1804
1805 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1806 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1807 MGMT_STATUS_INVALID_PARAMS);
1808 goto unlock;
1809 }
1810
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001811 hdev->major_class = cp->major;
1812 hdev->minor_class = cp->minor;
1813
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001814 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001815 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001816 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001817 goto unlock;
1818 }
1819
Johan Hedberg890ea892013-03-15 17:06:52 -05001820 hci_req_init(&req, hdev);
1821
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001822 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001823 hci_dev_unlock(hdev);
1824 cancel_delayed_work_sync(&hdev->service_cache);
1825 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001826 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001827 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001828
Johan Hedberg890ea892013-03-15 17:06:52 -05001829 update_class(&req);
1830
Johan Hedberg92da6092013-03-15 17:06:55 -05001831 err = hci_req_run(&req, set_class_complete);
1832 if (err < 0) {
1833 if (err != -ENODATA)
1834 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001835
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001836 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001837 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001838 goto unlock;
1839 }
1840
1841 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001842 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001843 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001844 goto unlock;
1845 }
1846
1847 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001848
Johan Hedbergb5235a62012-02-21 14:32:24 +02001849unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001850 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001851 return err;
1852}
1853
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001854static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001855 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001856{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001857 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001858 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001859 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001860
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001861 BT_DBG("request for %s", hdev->name);
1862
1863 if (!lmp_bredr_capable(hdev))
1864 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1865 MGMT_STATUS_NOT_SUPPORTED);
1866
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001867 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001868
Johan Hedberg86742e12011-11-07 23:13:38 +02001869 expected_len = sizeof(*cp) + key_count *
1870 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001871 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001872 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001873 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001874 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001875 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001876 }
1877
Johan Hedberg4ae143012013-01-20 14:27:13 +02001878 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1879 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1880 MGMT_STATUS_INVALID_PARAMS);
1881
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001882 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001883 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001884
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001885 for (i = 0; i < key_count; i++) {
1886 struct mgmt_link_key_info *key = &cp->keys[i];
1887
1888 if (key->addr.type != BDADDR_BREDR)
1889 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1890 MGMT_STATUS_INVALID_PARAMS);
1891 }
1892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001893 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001894
1895 hci_link_keys_clear(hdev);
1896
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001897 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001898 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001899 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001900 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001901
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001902 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001903 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001904
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001905 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001906 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001907 }
1908
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001909 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001910
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001911 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001912
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001913 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001914}
1915
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001916static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001917 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001918{
1919 struct mgmt_ev_device_unpaired ev;
1920
1921 bacpy(&ev.addr.bdaddr, bdaddr);
1922 ev.addr.type = addr_type;
1923
1924 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001925 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001926}
1927
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001928static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001929 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001930{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001931 struct mgmt_cp_unpair_device *cp = data;
1932 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001933 struct hci_cp_disconnect dc;
1934 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001935 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001936 int err;
1937
Johan Hedberga8a1d192011-11-10 15:54:38 +02001938 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001939 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1940 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001941
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001942 if (!bdaddr_type_is_valid(cp->addr.type))
1943 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1944 MGMT_STATUS_INVALID_PARAMS,
1945 &rp, sizeof(rp));
1946
Johan Hedberg118da702013-01-20 14:27:20 +02001947 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1948 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1949 MGMT_STATUS_INVALID_PARAMS,
1950 &rp, sizeof(rp));
1951
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001952 hci_dev_lock(hdev);
1953
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001954 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001955 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001956 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001957 goto unlock;
1958 }
1959
Andre Guedes591f47f2012-04-24 21:02:49 -03001960 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001961 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1962 else
1963 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001964
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001965 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001966 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001967 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001968 goto unlock;
1969 }
1970
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001971 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001972 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001973 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001974 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001975 else
1976 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001977 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001978 } else {
1979 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001980 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001981
Johan Hedberga8a1d192011-11-10 15:54:38 +02001982 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001983 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001984 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001985 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001986 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001987 }
1988
Johan Hedberg124f6e32012-02-09 13:50:12 +02001989 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001990 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001991 if (!cmd) {
1992 err = -ENOMEM;
1993 goto unlock;
1994 }
1995
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001996 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001997 dc.reason = 0x13; /* Remote User Terminated Connection */
1998 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1999 if (err < 0)
2000 mgmt_pending_remove(cmd);
2001
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002002unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002003 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002004 return err;
2005}
2006
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002007static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002008 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002009{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002010 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002011 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002012 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002013 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002014 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002015 int err;
2016
2017 BT_DBG("");
2018
Johan Hedberg06a63b12013-01-20 14:27:21 +02002019 memset(&rp, 0, sizeof(rp));
2020 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2021 rp.addr.type = cp->addr.type;
2022
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002023 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002024 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2025 MGMT_STATUS_INVALID_PARAMS,
2026 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002028 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002029
2030 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002031 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2032 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002033 goto failed;
2034 }
2035
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002036 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002037 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2038 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002039 goto failed;
2040 }
2041
Andre Guedes591f47f2012-04-24 21:02:49 -03002042 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002043 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2044 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002045 else
2046 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002047
Vishal Agarwalf9607272012-06-13 05:32:43 +05302048 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002049 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2050 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002051 goto failed;
2052 }
2053
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002054 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002055 if (!cmd) {
2056 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002057 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002058 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002059
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002060 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002061 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002062
2063 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2064 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002065 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002066
2067failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002068 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002069 return err;
2070}
2071
Andre Guedes57c14772012-04-24 21:02:50 -03002072static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002073{
2074 switch (link_type) {
2075 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002076 switch (addr_type) {
2077 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002078 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002079
Johan Hedberg48264f02011-11-09 13:58:58 +02002080 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002081 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002082 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002083 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002084
Johan Hedberg4c659c32011-11-07 23:13:39 +02002085 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002086 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002087 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002088 }
2089}
2090
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002091static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2092 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002093{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002094 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002095 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002096 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002097 int err;
2098 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002099
2100 BT_DBG("");
2101
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002102 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002103
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002104 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002105 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002106 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002107 goto unlock;
2108 }
2109
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002110 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002111 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2112 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002113 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002114 }
2115
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002116 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002117 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002118 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002119 err = -ENOMEM;
2120 goto unlock;
2121 }
2122
Johan Hedberg2784eb42011-01-21 13:56:35 +02002123 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002124 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002125 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2126 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002127 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002128 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002129 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002130 continue;
2131 i++;
2132 }
2133
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002134 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002135
Johan Hedberg4c659c32011-11-07 23:13:39 +02002136 /* Recalculate length in case of filtered SCO connections, etc */
2137 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002139 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002140 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002141
Johan Hedberga38528f2011-01-22 06:46:43 +02002142 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002143
2144unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002145 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002146 return err;
2147}
2148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002149static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002150 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002151{
2152 struct pending_cmd *cmd;
2153 int err;
2154
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002155 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002156 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002157 if (!cmd)
2158 return -ENOMEM;
2159
Johan Hedbergd8457692012-02-17 14:24:57 +02002160 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002161 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002162 if (err < 0)
2163 mgmt_pending_remove(cmd);
2164
2165 return err;
2166}
2167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002168static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002169 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002170{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002171 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002172 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002173 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002174 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002175 int err;
2176
2177 BT_DBG("");
2178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002179 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002180
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002181 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002182 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002183 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002184 goto failed;
2185 }
2186
Johan Hedbergd8457692012-02-17 14:24:57 +02002187 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002188 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002189 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002191 goto failed;
2192 }
2193
2194 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002195 struct mgmt_cp_pin_code_neg_reply ncp;
2196
2197 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002198
2199 BT_ERR("PIN code is not 16 bytes long");
2200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002201 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002202 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002203 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002204 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002205
2206 goto failed;
2207 }
2208
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002209 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002210 if (!cmd) {
2211 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002212 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002213 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002214
Johan Hedbergd8457692012-02-17 14:24:57 +02002215 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002216 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002217 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002218
2219 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2220 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002221 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002222
2223failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002224 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002225 return err;
2226}
2227
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002228static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2229 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002230{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002231 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002232
2233 BT_DBG("");
2234
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002235 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002236
2237 hdev->io_capability = cp->io_capability;
2238
2239 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002240 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002241
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002242 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002243
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002244 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2245 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002246}
2247
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002248static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002249{
2250 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002251 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002252
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002253 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002254 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2255 continue;
2256
Johan Hedberge9a416b2011-02-19 12:05:56 -03002257 if (cmd->user_data != conn)
2258 continue;
2259
2260 return cmd;
2261 }
2262
2263 return NULL;
2264}
2265
2266static void pairing_complete(struct pending_cmd *cmd, u8 status)
2267{
2268 struct mgmt_rp_pair_device rp;
2269 struct hci_conn *conn = cmd->user_data;
2270
Johan Hedbergba4e5642011-11-11 00:07:34 +02002271 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002272 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002273
Johan Hedbergaee9b212012-02-18 15:07:59 +02002274 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002275 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002276
2277 /* So we don't get further callbacks for this connection */
2278 conn->connect_cfm_cb = NULL;
2279 conn->security_cfm_cb = NULL;
2280 conn->disconn_cfm_cb = NULL;
2281
David Herrmann76a68ba2013-04-06 20:28:37 +02002282 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002283
Johan Hedberga664b5b2011-02-19 12:06:02 -03002284 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002285}
2286
2287static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2288{
2289 struct pending_cmd *cmd;
2290
2291 BT_DBG("status %u", status);
2292
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002293 cmd = find_pairing(conn);
2294 if (!cmd)
2295 BT_DBG("Unable to find a pending command");
2296 else
Johan Hedberge2113262012-02-18 15:20:03 +02002297 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002298}
2299
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302300static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2301{
2302 struct pending_cmd *cmd;
2303
2304 BT_DBG("status %u", status);
2305
2306 if (!status)
2307 return;
2308
2309 cmd = find_pairing(conn);
2310 if (!cmd)
2311 BT_DBG("Unable to find a pending command");
2312 else
2313 pairing_complete(cmd, mgmt_status(status));
2314}
2315
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002316static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002317 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002318{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002319 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002320 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002321 struct pending_cmd *cmd;
2322 u8 sec_level, auth_type;
2323 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002324 int err;
2325
2326 BT_DBG("");
2327
Szymon Jancf950a30e2013-01-18 12:48:07 +01002328 memset(&rp, 0, sizeof(rp));
2329 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2330 rp.addr.type = cp->addr.type;
2331
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002332 if (!bdaddr_type_is_valid(cp->addr.type))
2333 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2334 MGMT_STATUS_INVALID_PARAMS,
2335 &rp, sizeof(rp));
2336
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002337 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002338
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002339 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002340 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2341 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002342 goto unlock;
2343 }
2344
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002345 sec_level = BT_SECURITY_MEDIUM;
2346 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002347 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002348 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002349 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002350
Andre Guedes591f47f2012-04-24 21:02:49 -03002351 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002352 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2353 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002354 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002355 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2356 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002357
Ville Tervo30e76272011-02-22 16:10:53 -03002358 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002359 int status;
2360
2361 if (PTR_ERR(conn) == -EBUSY)
2362 status = MGMT_STATUS_BUSY;
2363 else
2364 status = MGMT_STATUS_CONNECT_FAILED;
2365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002366 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002367 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002368 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002369 goto unlock;
2370 }
2371
2372 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002373 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002376 goto unlock;
2377 }
2378
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002379 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002380 if (!cmd) {
2381 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002382 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002383 goto unlock;
2384 }
2385
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002386 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002387 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002388 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302389 else
2390 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002391
Johan Hedberge9a416b2011-02-19 12:05:56 -03002392 conn->security_cfm_cb = pairing_complete_cb;
2393 conn->disconn_cfm_cb = pairing_complete_cb;
2394 conn->io_capability = cp->io_cap;
2395 cmd->user_data = conn;
2396
2397 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002398 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002399 pairing_complete(cmd, 0);
2400
2401 err = 0;
2402
2403unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002404 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002405 return err;
2406}
2407
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002408static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2409 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002410{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002411 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002412 struct pending_cmd *cmd;
2413 struct hci_conn *conn;
2414 int err;
2415
2416 BT_DBG("");
2417
Johan Hedberg28424702012-02-02 04:02:29 +02002418 hci_dev_lock(hdev);
2419
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002420 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002421 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002422 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002423 goto unlock;
2424 }
2425
Johan Hedberg28424702012-02-02 04:02:29 +02002426 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2427 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002428 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002429 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002430 goto unlock;
2431 }
2432
2433 conn = cmd->user_data;
2434
2435 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002436 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002437 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002438 goto unlock;
2439 }
2440
2441 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2442
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002443 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002444 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002445unlock:
2446 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002447 return err;
2448}
2449
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002450static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002451 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002452 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002453{
Johan Hedberga5c29682011-02-19 12:05:57 -03002454 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002455 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002456 int err;
2457
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002458 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002459
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002460 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002461 err = cmd_complete(sk, hdev->id, mgmt_op,
2462 MGMT_STATUS_NOT_POWERED, addr,
2463 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002464 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002465 }
2466
Johan Hedberg1707c602013-03-15 17:07:15 -05002467 if (addr->type == BDADDR_BREDR)
2468 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002469 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002470 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002471
Johan Hedberg272d90d2012-02-09 15:26:12 +02002472 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002473 err = cmd_complete(sk, hdev->id, mgmt_op,
2474 MGMT_STATUS_NOT_CONNECTED, addr,
2475 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002476 goto done;
2477 }
2478
Johan Hedberg1707c602013-03-15 17:07:15 -05002479 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002480 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002481 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002482
Brian Gix5fe57d92011-12-21 16:12:13 -08002483 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002484 err = cmd_complete(sk, hdev->id, mgmt_op,
2485 MGMT_STATUS_SUCCESS, addr,
2486 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002487 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002488 err = cmd_complete(sk, hdev->id, mgmt_op,
2489 MGMT_STATUS_FAILED, addr,
2490 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002491
Brian Gix47c15e22011-11-16 13:53:14 -08002492 goto done;
2493 }
2494
Johan Hedberg1707c602013-03-15 17:07:15 -05002495 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002496 if (!cmd) {
2497 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002498 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002499 }
2500
Brian Gix0df4c182011-11-16 13:53:13 -08002501 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002502 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2503 struct hci_cp_user_passkey_reply cp;
2504
Johan Hedberg1707c602013-03-15 17:07:15 -05002505 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002506 cp.passkey = passkey;
2507 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2508 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002509 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2510 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002511
Johan Hedberga664b5b2011-02-19 12:06:02 -03002512 if (err < 0)
2513 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002514
Brian Gix0df4c182011-11-16 13:53:13 -08002515done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002516 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002517 return err;
2518}
2519
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302520static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2521 void *data, u16 len)
2522{
2523 struct mgmt_cp_pin_code_neg_reply *cp = data;
2524
2525 BT_DBG("");
2526
Johan Hedberg1707c602013-03-15 17:07:15 -05002527 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302528 MGMT_OP_PIN_CODE_NEG_REPLY,
2529 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2530}
2531
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2533 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002534{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002535 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002536
2537 BT_DBG("");
2538
2539 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002540 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002541 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002542
Johan Hedberg1707c602013-03-15 17:07:15 -05002543 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002544 MGMT_OP_USER_CONFIRM_REPLY,
2545 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002546}
2547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002548static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002549 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002550{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002551 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002552
2553 BT_DBG("");
2554
Johan Hedberg1707c602013-03-15 17:07:15 -05002555 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002556 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2557 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002558}
2559
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002560static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2561 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002562{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002563 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002564
2565 BT_DBG("");
2566
Johan Hedberg1707c602013-03-15 17:07:15 -05002567 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002568 MGMT_OP_USER_PASSKEY_REPLY,
2569 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002570}
2571
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002572static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002573 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002574{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002575 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002576
2577 BT_DBG("");
2578
Johan Hedberg1707c602013-03-15 17:07:15 -05002579 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2581 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002582}
2583
Johan Hedberg13928972013-03-15 17:07:00 -05002584static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002585{
Johan Hedberg13928972013-03-15 17:07:00 -05002586 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002587 struct hci_cp_write_local_name cp;
2588
Johan Hedberg13928972013-03-15 17:07:00 -05002589 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002590
Johan Hedberg890ea892013-03-15 17:06:52 -05002591 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002592}
2593
Johan Hedberg13928972013-03-15 17:07:00 -05002594static void set_name_complete(struct hci_dev *hdev, u8 status)
2595{
2596 struct mgmt_cp_set_local_name *cp;
2597 struct pending_cmd *cmd;
2598
2599 BT_DBG("status 0x%02x", status);
2600
2601 hci_dev_lock(hdev);
2602
2603 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2604 if (!cmd)
2605 goto unlock;
2606
2607 cp = cmd->param;
2608
2609 if (status)
2610 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2611 mgmt_status(status));
2612 else
2613 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2614 cp, sizeof(*cp));
2615
2616 mgmt_pending_remove(cmd);
2617
2618unlock:
2619 hci_dev_unlock(hdev);
2620}
2621
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002622static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002623 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002624{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002625 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002626 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002627 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002628 int err;
2629
2630 BT_DBG("");
2631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002632 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002633
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002634 /* If the old values are the same as the new ones just return a
2635 * direct command complete event.
2636 */
2637 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2638 !memcmp(hdev->short_name, cp->short_name,
2639 sizeof(hdev->short_name))) {
2640 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2641 data, len);
2642 goto failed;
2643 }
2644
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002645 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002646
Johan Hedbergb5235a62012-02-21 14:32:24 +02002647 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002648 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002649
2650 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002651 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002652 if (err < 0)
2653 goto failed;
2654
2655 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002656 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002657
Johan Hedbergb5235a62012-02-21 14:32:24 +02002658 goto failed;
2659 }
2660
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002661 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002662 if (!cmd) {
2663 err = -ENOMEM;
2664 goto failed;
2665 }
2666
Johan Hedberg13928972013-03-15 17:07:00 -05002667 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2668
Johan Hedberg890ea892013-03-15 17:06:52 -05002669 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002670
2671 if (lmp_bredr_capable(hdev)) {
2672 update_name(&req);
2673 update_eir(&req);
2674 }
2675
2676 if (lmp_le_capable(hdev))
2677 hci_update_ad(&req);
2678
Johan Hedberg13928972013-03-15 17:07:00 -05002679 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002680 if (err < 0)
2681 mgmt_pending_remove(cmd);
2682
2683failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002684 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002685 return err;
2686}
2687
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002688static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002689 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002690{
Szymon Jancc35938b2011-03-22 13:12:21 +01002691 struct pending_cmd *cmd;
2692 int err;
2693
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002694 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002695
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002696 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002697
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002698 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002699 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002701 goto unlock;
2702 }
2703
Andre Guedes9a1a1992012-07-24 15:03:48 -03002704 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002705 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002706 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002707 goto unlock;
2708 }
2709
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002710 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002711 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002712 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002713 goto unlock;
2714 }
2715
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002716 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002717 if (!cmd) {
2718 err = -ENOMEM;
2719 goto unlock;
2720 }
2721
2722 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2723 if (err < 0)
2724 mgmt_pending_remove(cmd);
2725
2726unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002727 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002728 return err;
2729}
2730
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002731static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002732 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002733{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002734 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002735 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002736 int err;
2737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002738 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002739
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002740 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002741
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002742 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002743 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002744 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002745 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002746 else
Szymon Janca6785be2012-12-13 15:11:21 +01002747 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002749 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002750 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002752 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002753 return err;
2754}
2755
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002756static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002757 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002758{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002759 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002760 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002761 int err;
2762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002763 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002764
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002765 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002766
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002767 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002768 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002769 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002770 else
Szymon Janca6785be2012-12-13 15:11:21 +01002771 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002772
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002773 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002774 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002775
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002776 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002777 return err;
2778}
2779
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002780static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2781{
2782 struct pending_cmd *cmd;
2783 u8 type;
2784 int err;
2785
2786 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2787
2788 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2789 if (!cmd)
2790 return -ENOENT;
2791
2792 type = hdev->discovery.type;
2793
2794 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2795 &type, sizeof(type));
2796 mgmt_pending_remove(cmd);
2797
2798 return err;
2799}
2800
Andre Guedes7c307722013-04-30 15:29:28 -03002801static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2802{
2803 BT_DBG("status %d", status);
2804
2805 if (status) {
2806 hci_dev_lock(hdev);
2807 mgmt_start_discovery_failed(hdev, status);
2808 hci_dev_unlock(hdev);
2809 return;
2810 }
2811
2812 hci_dev_lock(hdev);
2813 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2814 hci_dev_unlock(hdev);
2815
2816 switch (hdev->discovery.type) {
2817 case DISCOV_TYPE_LE:
2818 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002819 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002820 break;
2821
2822 case DISCOV_TYPE_INTERLEAVED:
2823 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002824 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002825 break;
2826
2827 case DISCOV_TYPE_BREDR:
2828 break;
2829
2830 default:
2831 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2832 }
2833}
2834
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002835static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002836 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002837{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002838 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002839 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002840 struct hci_cp_le_set_scan_param param_cp;
2841 struct hci_cp_le_set_scan_enable enable_cp;
2842 struct hci_cp_inquiry inq_cp;
2843 struct hci_request req;
2844 /* General inquiry access code (GIAC) */
2845 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002846 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002847 int err;
2848
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002849 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002851 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002852
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002853 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002854 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002855 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002856 goto failed;
2857 }
2858
Andre Guedes642be6c2012-03-21 00:03:37 -03002859 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2860 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2861 MGMT_STATUS_BUSY);
2862 goto failed;
2863 }
2864
Johan Hedbergff9ef572012-01-04 14:23:45 +02002865 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002866 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002867 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002868 goto failed;
2869 }
2870
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002871 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002872 if (!cmd) {
2873 err = -ENOMEM;
2874 goto failed;
2875 }
2876
Andre Guedes4aab14e2012-02-17 20:39:36 -03002877 hdev->discovery.type = cp->type;
2878
Andre Guedes7c307722013-04-30 15:29:28 -03002879 hci_req_init(&req, hdev);
2880
Andre Guedes4aab14e2012-02-17 20:39:36 -03002881 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002882 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002883 status = mgmt_bredr_support(hdev);
2884 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002885 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002886 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002887 mgmt_pending_remove(cmd);
2888 goto failed;
2889 }
2890
Andre Guedes7c307722013-04-30 15:29:28 -03002891 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2892 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2893 MGMT_STATUS_BUSY);
2894 mgmt_pending_remove(cmd);
2895 goto failed;
2896 }
2897
2898 hci_inquiry_cache_flush(hdev);
2899
2900 memset(&inq_cp, 0, sizeof(inq_cp));
2901 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002902 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002903 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002904 break;
2905
2906 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002907 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002908 status = mgmt_le_support(hdev);
2909 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002910 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002911 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002912 mgmt_pending_remove(cmd);
2913 goto failed;
2914 }
2915
Andre Guedes7c307722013-04-30 15:29:28 -03002916 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002917 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002918 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2919 MGMT_STATUS_NOT_SUPPORTED);
2920 mgmt_pending_remove(cmd);
2921 goto failed;
2922 }
2923
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002924 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002925 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2926 MGMT_STATUS_REJECTED);
2927 mgmt_pending_remove(cmd);
2928 goto failed;
2929 }
2930
2931 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2932 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2933 MGMT_STATUS_BUSY);
2934 mgmt_pending_remove(cmd);
2935 goto failed;
2936 }
2937
2938 memset(&param_cp, 0, sizeof(param_cp));
2939 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002940 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2941 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002942 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2943 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2944 else
2945 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002946 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2947 &param_cp);
2948
2949 memset(&enable_cp, 0, sizeof(enable_cp));
2950 enable_cp.enable = LE_SCAN_ENABLE;
2951 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2952 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2953 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002954 break;
2955
Andre Guedesf39799f2012-02-17 20:39:35 -03002956 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002957 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2958 MGMT_STATUS_INVALID_PARAMS);
2959 mgmt_pending_remove(cmd);
2960 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002961 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002962
Andre Guedes7c307722013-04-30 15:29:28 -03002963 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002964 if (err < 0)
2965 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002966 else
2967 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002968
2969failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002970 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002971 return err;
2972}
2973
Andre Guedes1183fdc2013-04-30 15:29:35 -03002974static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2975{
2976 struct pending_cmd *cmd;
2977 int err;
2978
2979 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2980 if (!cmd)
2981 return -ENOENT;
2982
2983 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2984 &hdev->discovery.type, sizeof(hdev->discovery.type));
2985 mgmt_pending_remove(cmd);
2986
2987 return err;
2988}
2989
Andre Guedes0e05bba2013-04-30 15:29:33 -03002990static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2991{
2992 BT_DBG("status %d", status);
2993
2994 hci_dev_lock(hdev);
2995
2996 if (status) {
2997 mgmt_stop_discovery_failed(hdev, status);
2998 goto unlock;
2999 }
3000
3001 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3002
3003unlock:
3004 hci_dev_unlock(hdev);
3005}
3006
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003007static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003008 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003009{
Johan Hedbergd9306502012-02-20 23:25:18 +02003010 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003011 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003012 struct hci_cp_remote_name_req_cancel cp;
3013 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003014 struct hci_request req;
3015 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003016 int err;
3017
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003018 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003019
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003020 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003021
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003022 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003023 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003024 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3025 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003026 goto unlock;
3027 }
3028
3029 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003030 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003031 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3032 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003033 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003034 }
3035
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003036 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003037 if (!cmd) {
3038 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003039 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003040 }
3041
Andre Guedes0e05bba2013-04-30 15:29:33 -03003042 hci_req_init(&req, hdev);
3043
Andre Guedese0d9727e2012-03-20 15:15:36 -03003044 switch (hdev->discovery.state) {
3045 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003046 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3047 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3048 } else {
3049 cancel_delayed_work(&hdev->le_scan_disable);
3050
3051 memset(&enable_cp, 0, sizeof(enable_cp));
3052 enable_cp.enable = LE_SCAN_DISABLE;
3053 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3054 sizeof(enable_cp), &enable_cp);
3055 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003056
Andre Guedese0d9727e2012-03-20 15:15:36 -03003057 break;
3058
3059 case DISCOVERY_RESOLVING:
3060 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003061 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003062 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003063 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003064 err = cmd_complete(sk, hdev->id,
3065 MGMT_OP_STOP_DISCOVERY, 0,
3066 &mgmt_cp->type,
3067 sizeof(mgmt_cp->type));
3068 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3069 goto unlock;
3070 }
3071
3072 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003073 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3074 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003075
3076 break;
3077
3078 default:
3079 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003080
3081 mgmt_pending_remove(cmd);
3082 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3083 MGMT_STATUS_FAILED, &mgmt_cp->type,
3084 sizeof(mgmt_cp->type));
3085 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003086 }
3087
Andre Guedes0e05bba2013-04-30 15:29:33 -03003088 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003089 if (err < 0)
3090 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003091 else
3092 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003093
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003094unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003095 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003096 return err;
3097}
3098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003099static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003100 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003101{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003102 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003103 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003104 int err;
3105
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003106 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003107
Johan Hedberg561aafb2012-01-04 13:31:59 +02003108 hci_dev_lock(hdev);
3109
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003110 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003111 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003112 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003113 goto failed;
3114 }
3115
Johan Hedberga198e7b2012-02-17 14:27:06 +02003116 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003117 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003118 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003119 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003120 goto failed;
3121 }
3122
3123 if (cp->name_known) {
3124 e->name_state = NAME_KNOWN;
3125 list_del(&e->list);
3126 } else {
3127 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003128 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003129 }
3130
Johan Hedberge3846622013-01-09 15:29:33 +02003131 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3132 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003133
3134failed:
3135 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003136 return err;
3137}
3138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003139static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003140 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003142 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003143 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003144 int err;
3145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003146 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003147
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003148 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003149 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3150 MGMT_STATUS_INVALID_PARAMS,
3151 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003153 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003154
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003155 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003156 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003157 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003158 else
Szymon Janca6785be2012-12-13 15:11:21 +01003159 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003161 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003162 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003163
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003164 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003165
3166 return err;
3167}
3168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003169static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003170 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003171{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003172 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003173 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003174 int err;
3175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003176 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003177
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003178 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003179 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3180 MGMT_STATUS_INVALID_PARAMS,
3181 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003182
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003183 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003184
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003185 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003186 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003187 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003188 else
Szymon Janca6785be2012-12-13 15:11:21 +01003189 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003190
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003191 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003192 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003193
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003194 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003195
3196 return err;
3197}
3198
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003199static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3200 u16 len)
3201{
3202 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003203 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003204 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003205 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003206
3207 BT_DBG("%s", hdev->name);
3208
Szymon Jancc72d4b82012-03-16 16:02:57 +01003209 source = __le16_to_cpu(cp->source);
3210
3211 if (source > 0x0002)
3212 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3213 MGMT_STATUS_INVALID_PARAMS);
3214
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003215 hci_dev_lock(hdev);
3216
Szymon Jancc72d4b82012-03-16 16:02:57 +01003217 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003218 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3219 hdev->devid_product = __le16_to_cpu(cp->product);
3220 hdev->devid_version = __le16_to_cpu(cp->version);
3221
3222 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3223
Johan Hedberg890ea892013-03-15 17:06:52 -05003224 hci_req_init(&req, hdev);
3225 update_eir(&req);
3226 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003227
3228 hci_dev_unlock(hdev);
3229
3230 return err;
3231}
3232
Johan Hedberg4375f102013-09-25 13:26:10 +03003233static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3234{
3235 struct cmd_lookup match = { NULL, hdev };
3236
3237 if (status) {
3238 u8 mgmt_err = mgmt_status(status);
3239
3240 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3241 cmd_status_rsp, &mgmt_err);
3242 return;
3243 }
3244
3245 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3246 &match);
3247
3248 new_settings(hdev, match.sk);
3249
3250 if (match.sk)
3251 sock_put(match.sk);
3252}
3253
3254static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3255{
3256 struct mgmt_mode *cp = data;
3257 struct pending_cmd *cmd;
3258 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003259 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003260 int err;
3261
3262 BT_DBG("request for %s", hdev->name);
3263
Johan Hedberge6fe7982013-10-02 15:45:22 +03003264 status = mgmt_le_support(hdev);
3265 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003266 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003267 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003268
3269 if (cp->val != 0x00 && cp->val != 0x01)
3270 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3271 MGMT_STATUS_INVALID_PARAMS);
3272
3273 hci_dev_lock(hdev);
3274
3275 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003276 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003277
3278 if (!hdev_is_powered(hdev) || val == enabled) {
3279 bool changed = false;
3280
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003281 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3282 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003283 changed = true;
3284 }
3285
3286 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3287 if (err < 0)
3288 goto unlock;
3289
3290 if (changed)
3291 err = new_settings(hdev, sk);
3292
3293 goto unlock;
3294 }
3295
3296 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3297 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3298 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3299 MGMT_STATUS_BUSY);
3300 goto unlock;
3301 }
3302
3303 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3304 if (!cmd) {
3305 err = -ENOMEM;
3306 goto unlock;
3307 }
3308
3309 hci_req_init(&req, hdev);
3310
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003311 if (val)
3312 enable_advertising(&req);
3313 else
3314 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003315
3316 err = hci_req_run(&req, set_advertising_complete);
3317 if (err < 0)
3318 mgmt_pending_remove(cmd);
3319
3320unlock:
3321 hci_dev_unlock(hdev);
3322 return err;
3323}
3324
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003325static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3326 void *data, u16 len)
3327{
3328 struct mgmt_cp_set_static_address *cp = data;
3329 int err;
3330
3331 BT_DBG("%s", hdev->name);
3332
Marcel Holtmann62af4442013-10-02 22:10:32 -07003333 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003334 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003335 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003336
3337 if (hdev_is_powered(hdev))
3338 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3339 MGMT_STATUS_REJECTED);
3340
3341 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3342 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3343 return cmd_status(sk, hdev->id,
3344 MGMT_OP_SET_STATIC_ADDRESS,
3345 MGMT_STATUS_INVALID_PARAMS);
3346
3347 /* Two most significant bits shall be set */
3348 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3349 return cmd_status(sk, hdev->id,
3350 MGMT_OP_SET_STATIC_ADDRESS,
3351 MGMT_STATUS_INVALID_PARAMS);
3352 }
3353
3354 hci_dev_lock(hdev);
3355
3356 bacpy(&hdev->static_addr, &cp->bdaddr);
3357
3358 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3359
3360 hci_dev_unlock(hdev);
3361
3362 return err;
3363}
3364
Johan Hedberg33e38b32013-03-15 17:07:05 -05003365static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3366{
3367 struct pending_cmd *cmd;
3368
3369 BT_DBG("status 0x%02x", status);
3370
3371 hci_dev_lock(hdev);
3372
3373 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3374 if (!cmd)
3375 goto unlock;
3376
3377 if (status) {
3378 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3379 mgmt_status(status));
3380 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003381 struct mgmt_mode *cp = cmd->param;
3382
3383 if (cp->val)
3384 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3385 else
3386 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3387
Johan Hedberg33e38b32013-03-15 17:07:05 -05003388 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3389 new_settings(hdev, cmd->sk);
3390 }
3391
3392 mgmt_pending_remove(cmd);
3393
3394unlock:
3395 hci_dev_unlock(hdev);
3396}
3397
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003398static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003399 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003400{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003401 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003402 struct pending_cmd *cmd;
3403 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003404 int err;
3405
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003406 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003407
Johan Hedberg56f87902013-10-02 13:43:13 +03003408 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3409 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003410 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3411 MGMT_STATUS_NOT_SUPPORTED);
3412
Johan Hedberga7e80f22013-01-09 16:05:19 +02003413 if (cp->val != 0x00 && cp->val != 0x01)
3414 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3415 MGMT_STATUS_INVALID_PARAMS);
3416
Johan Hedberg5400c042012-02-21 16:40:33 +02003417 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003418 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003419 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003420
3421 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003422 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003423 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003424
3425 hci_dev_lock(hdev);
3426
Johan Hedberg05cbf292013-03-15 17:07:07 -05003427 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3428 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3429 MGMT_STATUS_BUSY);
3430 goto unlock;
3431 }
3432
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003433 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3434 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3435 hdev);
3436 goto unlock;
3437 }
3438
Johan Hedberg33e38b32013-03-15 17:07:05 -05003439 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3440 data, len);
3441 if (!cmd) {
3442 err = -ENOMEM;
3443 goto unlock;
3444 }
3445
3446 hci_req_init(&req, hdev);
3447
Johan Hedberg406d7802013-03-15 17:07:09 -05003448 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003449
3450 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003451 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003452 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003453 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003454 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003455 }
3456
Johan Hedberg33e38b32013-03-15 17:07:05 -05003457unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003458 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003459
Antti Julkuf6422ec2011-06-22 13:11:56 +03003460 return err;
3461}
3462
Johan Hedberg0663ca22013-10-02 13:43:14 +03003463static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3464{
3465 struct pending_cmd *cmd;
3466
3467 BT_DBG("status 0x%02x", status);
3468
3469 hci_dev_lock(hdev);
3470
3471 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3472 if (!cmd)
3473 goto unlock;
3474
3475 if (status) {
3476 u8 mgmt_err = mgmt_status(status);
3477
3478 /* We need to restore the flag if related HCI commands
3479 * failed.
3480 */
3481 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3482
3483 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3484 } else {
3485 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3486 new_settings(hdev, cmd->sk);
3487 }
3488
3489 mgmt_pending_remove(cmd);
3490
3491unlock:
3492 hci_dev_unlock(hdev);
3493}
3494
3495static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3496{
3497 struct mgmt_mode *cp = data;
3498 struct pending_cmd *cmd;
3499 struct hci_request req;
3500 int err;
3501
3502 BT_DBG("request for %s", hdev->name);
3503
3504 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3505 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3506 MGMT_STATUS_NOT_SUPPORTED);
3507
3508 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3509 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3510 MGMT_STATUS_REJECTED);
3511
3512 if (cp->val != 0x00 && cp->val != 0x01)
3513 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3514 MGMT_STATUS_INVALID_PARAMS);
3515
3516 hci_dev_lock(hdev);
3517
3518 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3519 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3520 goto unlock;
3521 }
3522
3523 if (!hdev_is_powered(hdev)) {
3524 if (!cp->val) {
3525 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3526 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3527 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3528 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3529 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3530 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3531 }
3532
3533 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3534
3535 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3536 if (err < 0)
3537 goto unlock;
3538
3539 err = new_settings(hdev, sk);
3540 goto unlock;
3541 }
3542
3543 /* Reject disabling when powered on */
3544 if (!cp->val) {
3545 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3546 MGMT_STATUS_REJECTED);
3547 goto unlock;
3548 }
3549
3550 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3551 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3552 MGMT_STATUS_BUSY);
3553 goto unlock;
3554 }
3555
3556 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3557 if (!cmd) {
3558 err = -ENOMEM;
3559 goto unlock;
3560 }
3561
3562 /* We need to flip the bit already here so that hci_update_ad
3563 * generates the correct flags.
3564 */
3565 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3566
3567 hci_req_init(&req, hdev);
3568 hci_update_ad(&req);
3569 err = hci_req_run(&req, set_bredr_complete);
3570 if (err < 0)
3571 mgmt_pending_remove(cmd);
3572
3573unlock:
3574 hci_dev_unlock(hdev);
3575 return err;
3576}
3577
Johan Hedberg3f706b72013-01-20 14:27:16 +02003578static bool ltk_is_valid(struct mgmt_ltk_info *key)
3579{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003580 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3581 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003582 if (key->master != 0x00 && key->master != 0x01)
3583 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003584 if (!bdaddr_type_is_le(key->addr.type))
3585 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003586 return true;
3587}
3588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003589static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003590 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003591{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003592 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3593 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003594 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003595
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003596 BT_DBG("request for %s", hdev->name);
3597
3598 if (!lmp_le_capable(hdev))
3599 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3600 MGMT_STATUS_NOT_SUPPORTED);
3601
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003602 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003603
3604 expected_len = sizeof(*cp) + key_count *
3605 sizeof(struct mgmt_ltk_info);
3606 if (expected_len != len) {
3607 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003608 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003609 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003610 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003611 }
3612
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003613 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003614
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003615 for (i = 0; i < key_count; i++) {
3616 struct mgmt_ltk_info *key = &cp->keys[i];
3617
Johan Hedberg3f706b72013-01-20 14:27:16 +02003618 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003619 return cmd_status(sk, hdev->id,
3620 MGMT_OP_LOAD_LONG_TERM_KEYS,
3621 MGMT_STATUS_INVALID_PARAMS);
3622 }
3623
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003624 hci_dev_lock(hdev);
3625
3626 hci_smp_ltks_clear(hdev);
3627
3628 for (i = 0; i < key_count; i++) {
3629 struct mgmt_ltk_info *key = &cp->keys[i];
3630 u8 type;
3631
3632 if (key->master)
3633 type = HCI_SMP_LTK;
3634 else
3635 type = HCI_SMP_LTK_SLAVE;
3636
Hemant Gupta4596fde2012-04-16 14:57:40 +05303637 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003638 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003639 type, 0, key->authenticated, key->val,
3640 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003641 }
3642
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003643 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3644 NULL, 0);
3645
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003646 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003647
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003648 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003649}
3650
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003651static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003652 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3653 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003654 bool var_len;
3655 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003656} mgmt_handlers[] = {
3657 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003658 { read_version, false, MGMT_READ_VERSION_SIZE },
3659 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3660 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3661 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3662 { set_powered, false, MGMT_SETTING_SIZE },
3663 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3664 { set_connectable, false, MGMT_SETTING_SIZE },
3665 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3666 { set_pairable, false, MGMT_SETTING_SIZE },
3667 { set_link_security, false, MGMT_SETTING_SIZE },
3668 { set_ssp, false, MGMT_SETTING_SIZE },
3669 { set_hs, false, MGMT_SETTING_SIZE },
3670 { set_le, false, MGMT_SETTING_SIZE },
3671 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3672 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3673 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3674 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3675 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3676 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3677 { disconnect, false, MGMT_DISCONNECT_SIZE },
3678 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3679 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3680 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3681 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3682 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3683 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3684 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3685 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3686 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3687 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3688 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3689 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3690 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3691 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3692 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3693 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3694 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3695 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3696 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003697 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003698 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003699 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003700 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003701};
3702
3703
Johan Hedberg03811012010-12-08 00:21:06 +02003704int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3705{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003706 void *buf;
3707 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003708 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003709 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003710 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003711 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003712 int err;
3713
3714 BT_DBG("got %zu bytes", msglen);
3715
3716 if (msglen < sizeof(*hdr))
3717 return -EINVAL;
3718
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003719 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003720 if (!buf)
3721 return -ENOMEM;
3722
3723 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3724 err = -EFAULT;
3725 goto done;
3726 }
3727
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003728 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003729 opcode = __le16_to_cpu(hdr->opcode);
3730 index = __le16_to_cpu(hdr->index);
3731 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003732
3733 if (len != msglen - sizeof(*hdr)) {
3734 err = -EINVAL;
3735 goto done;
3736 }
3737
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003738 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003739 hdev = hci_dev_get(index);
3740 if (!hdev) {
3741 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003742 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003743 goto done;
3744 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003745
3746 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3747 err = cmd_status(sk, index, opcode,
3748 MGMT_STATUS_INVALID_INDEX);
3749 goto done;
3750 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003751 }
3752
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003753 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003754 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003755 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003756 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003757 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003758 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003759 }
3760
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003761 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003762 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003763 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003764 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003765 goto done;
3766 }
3767
Johan Hedbergbe22b542012-03-01 22:24:41 +02003768 handler = &mgmt_handlers[opcode];
3769
3770 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003771 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003772 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003773 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003774 goto done;
3775 }
3776
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003777 if (hdev)
3778 mgmt_init_hdev(sk, hdev);
3779
3780 cp = buf + sizeof(*hdr);
3781
Johan Hedbergbe22b542012-03-01 22:24:41 +02003782 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003783 if (err < 0)
3784 goto done;
3785
Johan Hedberg03811012010-12-08 00:21:06 +02003786 err = msglen;
3787
3788done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003789 if (hdev)
3790 hci_dev_put(hdev);
3791
Johan Hedberg03811012010-12-08 00:21:06 +02003792 kfree(buf);
3793 return err;
3794}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003795
Johan Hedberg744cf192011-11-08 20:40:14 +02003796int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003797{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003798 if (!mgmt_valid_hdev(hdev))
3799 return -ENOTSUPP;
3800
Johan Hedberg744cf192011-11-08 20:40:14 +02003801 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003802}
3803
Johan Hedberg744cf192011-11-08 20:40:14 +02003804int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003805{
Johan Hedberg5f159032012-03-02 03:13:19 +02003806 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003807
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003808 if (!mgmt_valid_hdev(hdev))
3809 return -ENOTSUPP;
3810
Johan Hedberg744cf192011-11-08 20:40:14 +02003811 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003812
Johan Hedberg744cf192011-11-08 20:40:14 +02003813 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003814}
3815
Johan Hedberg890ea892013-03-15 17:06:52 -05003816static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003817{
Johan Hedberg890ea892013-03-15 17:06:52 -05003818 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003819 u8 scan = 0;
3820
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003821 /* Ensure that fast connectable is disabled. This function will
3822 * not do anything if the page scan parameters are already what
3823 * they should be.
3824 */
3825 write_fast_connectable(req, false);
3826
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003827 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3828 scan |= SCAN_PAGE;
3829 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3830 scan |= SCAN_INQUIRY;
3831
Johan Hedberg890ea892013-03-15 17:06:52 -05003832 if (scan)
3833 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003834}
3835
Johan Hedberg229ab392013-03-15 17:06:53 -05003836static void powered_complete(struct hci_dev *hdev, u8 status)
3837{
3838 struct cmd_lookup match = { NULL, hdev };
3839
3840 BT_DBG("status 0x%02x", status);
3841
3842 hci_dev_lock(hdev);
3843
3844 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3845
3846 new_settings(hdev, match.sk);
3847
3848 hci_dev_unlock(hdev);
3849
3850 if (match.sk)
3851 sock_put(match.sk);
3852}
3853
Johan Hedberg70da6242013-03-15 17:06:51 -05003854static int powered_update_hci(struct hci_dev *hdev)
3855{
Johan Hedberg890ea892013-03-15 17:06:52 -05003856 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003857 u8 link_sec;
3858
Johan Hedberg890ea892013-03-15 17:06:52 -05003859 hci_req_init(&req, hdev);
3860
Johan Hedberg70da6242013-03-15 17:06:51 -05003861 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3862 !lmp_host_ssp_capable(hdev)) {
3863 u8 ssp = 1;
3864
Johan Hedberg890ea892013-03-15 17:06:52 -05003865 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003866 }
3867
Johan Hedbergc73eee92013-04-19 18:35:21 +03003868 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3869 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003870 struct hci_cp_write_le_host_supported cp;
3871
3872 cp.le = 1;
3873 cp.simul = lmp_le_br_capable(hdev);
3874
3875 /* Check first if we already have the right
3876 * host state (host features set)
3877 */
3878 if (cp.le != lmp_host_le_capable(hdev) ||
3879 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003880 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3881 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003882
3883 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3884 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003885 }
3886
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003887 if (lmp_le_capable(hdev)) {
3888 /* Set random address to static address if configured */
3889 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3890 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3891 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003892
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003893 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3894 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003895 }
3896
Johan Hedberg70da6242013-03-15 17:06:51 -05003897 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3898 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003899 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3900 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003901
3902 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003903 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3904 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003905 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003906 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003907 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003908 }
3909
Johan Hedberg229ab392013-03-15 17:06:53 -05003910 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003911}
3912
Johan Hedberg744cf192011-11-08 20:40:14 +02003913int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003914{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003915 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003916 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3917 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003918 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003919
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003920 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3921 return 0;
3922
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003923 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003924 if (powered_update_hci(hdev) == 0)
3925 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003926
Johan Hedberg229ab392013-03-15 17:06:53 -05003927 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3928 &match);
3929 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003930 }
3931
Johan Hedberg229ab392013-03-15 17:06:53 -05003932 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3933 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3934
3935 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3936 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3937 zero_cod, sizeof(zero_cod), NULL);
3938
3939new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003940 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003941
3942 if (match.sk)
3943 sock_put(match.sk);
3944
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003945 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003946}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003947
Johan Hedberg96570ff2013-05-29 09:51:29 +03003948int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3949{
3950 struct pending_cmd *cmd;
3951 u8 status;
3952
3953 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3954 if (!cmd)
3955 return -ENOENT;
3956
3957 if (err == -ERFKILL)
3958 status = MGMT_STATUS_RFKILLED;
3959 else
3960 status = MGMT_STATUS_FAILED;
3961
3962 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3963
3964 mgmt_pending_remove(cmd);
3965
3966 return err;
3967}
3968
Johan Hedberg744cf192011-11-08 20:40:14 +02003969int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003970{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003971 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003972 bool changed = false;
3973 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003974
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003975 if (discoverable) {
3976 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3977 changed = true;
3978 } else {
3979 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3980 changed = true;
3981 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003982
Johan Hedberged9b5f22012-02-21 20:47:06 +02003983 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003984 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003985
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003986 if (changed)
3987 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003988
Johan Hedberg73f22f62010-12-29 16:00:25 +02003989 if (match.sk)
3990 sock_put(match.sk);
3991
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003992 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003993}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003994
Johan Hedberg744cf192011-11-08 20:40:14 +02003995int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003996{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003997 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003998 bool changed = false;
3999 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004000
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004001 if (connectable) {
4002 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4003 changed = true;
4004 } else {
4005 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4006 changed = true;
4007 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004008
Johan Hedberg2b76f452013-03-15 17:07:04 -05004009 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004010
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004011 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004012 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004013
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004014 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004015}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004016
Johan Hedberg744cf192011-11-08 20:40:14 +02004017int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004018{
Johan Hedbergca69b792011-11-11 18:10:00 +02004019 u8 mgmt_err = mgmt_status(status);
4020
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004021 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004022 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004023 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004024
4025 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004026 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004027 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004028
4029 return 0;
4030}
4031
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004032int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4033 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004034{
Johan Hedberg86742e12011-11-07 23:13:38 +02004035 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004036
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004037 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004038
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004039 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004040 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004041 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004042 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004043 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004044 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004045
Johan Hedberg744cf192011-11-08 20:40:14 +02004046 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004047}
Johan Hedbergf7520542011-01-20 12:34:39 +02004048
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004049int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4050{
4051 struct mgmt_ev_new_long_term_key ev;
4052
4053 memset(&ev, 0, sizeof(ev));
4054
4055 ev.store_hint = persistent;
4056 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004057 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004058 ev.key.authenticated = key->authenticated;
4059 ev.key.enc_size = key->enc_size;
4060 ev.key.ediv = key->ediv;
4061
4062 if (key->type == HCI_SMP_LTK)
4063 ev.key.master = 1;
4064
4065 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4066 memcpy(ev.key.val, key->val, sizeof(key->val));
4067
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004068 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4069 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004070}
4071
Johan Hedbergafc747a2012-01-15 18:11:07 +02004072int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004073 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4074 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004075{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004076 char buf[512];
4077 struct mgmt_ev_device_connected *ev = (void *) buf;
4078 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004079
Johan Hedbergb644ba32012-01-17 21:48:47 +02004080 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004081 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004082
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004083 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004084
Johan Hedbergb644ba32012-01-17 21:48:47 +02004085 if (name_len > 0)
4086 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004087 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004088
4089 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004090 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004091 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004092
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004093 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004094
4095 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004096 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004097}
4098
Johan Hedberg8962ee72011-01-20 12:40:27 +02004099static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4100{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004101 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004102 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004103 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004104
Johan Hedberg88c3df12012-02-09 14:27:38 +02004105 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4106 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004107
Johan Hedbergaee9b212012-02-18 15:07:59 +02004108 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004109 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004110
4111 *sk = cmd->sk;
4112 sock_hold(*sk);
4113
Johan Hedberga664b5b2011-02-19 12:06:02 -03004114 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004115}
4116
Johan Hedberg124f6e32012-02-09 13:50:12 +02004117static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004118{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004119 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004120 struct mgmt_cp_unpair_device *cp = cmd->param;
4121 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004122
4123 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004124 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4125 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004126
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004127 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4128
Johan Hedbergaee9b212012-02-18 15:07:59 +02004129 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004130
4131 mgmt_pending_remove(cmd);
4132}
4133
Johan Hedbergafc747a2012-01-15 18:11:07 +02004134int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004135 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004136{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004137 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004138 struct sock *sk = NULL;
4139 int err;
4140
Johan Hedberg744cf192011-11-08 20:40:14 +02004141 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004142
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004143 bacpy(&ev.addr.bdaddr, bdaddr);
4144 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4145 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004146
Johan Hedbergafc747a2012-01-15 18:11:07 +02004147 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004148 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004149
4150 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004151 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004152
Johan Hedberg124f6e32012-02-09 13:50:12 +02004153 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004154 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004155
Johan Hedberg8962ee72011-01-20 12:40:27 +02004156 return err;
4157}
4158
Johan Hedberg88c3df12012-02-09 14:27:38 +02004159int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004160 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004161{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004162 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004163 struct pending_cmd *cmd;
4164 int err;
4165
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004166 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4167 hdev);
4168
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004169 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004170 if (!cmd)
4171 return -ENOENT;
4172
Johan Hedberg88c3df12012-02-09 14:27:38 +02004173 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004174 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004175
Johan Hedberg88c3df12012-02-09 14:27:38 +02004176 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004177 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004178
Johan Hedberga664b5b2011-02-19 12:06:02 -03004179 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004180
4181 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004182}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004183
Johan Hedberg48264f02011-11-09 13:58:58 +02004184int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004185 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004186{
4187 struct mgmt_ev_connect_failed ev;
4188
Johan Hedberg4c659c32011-11-07 23:13:39 +02004189 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004190 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004191 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004192
Johan Hedberg744cf192011-11-08 20:40:14 +02004193 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004194}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004195
Johan Hedberg744cf192011-11-08 20:40:14 +02004196int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004197{
4198 struct mgmt_ev_pin_code_request ev;
4199
Johan Hedbergd8457692012-02-17 14:24:57 +02004200 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004201 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004202 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004203
Johan Hedberg744cf192011-11-08 20:40:14 +02004204 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004205 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004206}
4207
Johan Hedberg744cf192011-11-08 20:40:14 +02004208int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004209 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004210{
4211 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004212 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004213 int err;
4214
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004215 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004216 if (!cmd)
4217 return -ENOENT;
4218
Johan Hedbergd8457692012-02-17 14:24:57 +02004219 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004220 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004221
Johan Hedbergaee9b212012-02-18 15:07:59 +02004222 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004223 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004224
Johan Hedberga664b5b2011-02-19 12:06:02 -03004225 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004226
4227 return err;
4228}
4229
Johan Hedberg744cf192011-11-08 20:40:14 +02004230int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004231 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004232{
4233 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004234 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004235 int err;
4236
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004237 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004238 if (!cmd)
4239 return -ENOENT;
4240
Johan Hedbergd8457692012-02-17 14:24:57 +02004241 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004242 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004243
Johan Hedbergaee9b212012-02-18 15:07:59 +02004244 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004245 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004246
Johan Hedberga664b5b2011-02-19 12:06:02 -03004247 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004248
4249 return err;
4250}
Johan Hedberga5c29682011-02-19 12:05:57 -03004251
Johan Hedberg744cf192011-11-08 20:40:14 +02004252int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004253 u8 link_type, u8 addr_type, __le32 value,
4254 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004255{
4256 struct mgmt_ev_user_confirm_request ev;
4257
Johan Hedberg744cf192011-11-08 20:40:14 +02004258 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004259
Johan Hedberg272d90d2012-02-09 15:26:12 +02004260 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004261 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004262 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004263 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004264
Johan Hedberg744cf192011-11-08 20:40:14 +02004265 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004266 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004267}
4268
Johan Hedberg272d90d2012-02-09 15:26:12 +02004269int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004270 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004271{
4272 struct mgmt_ev_user_passkey_request ev;
4273
4274 BT_DBG("%s", hdev->name);
4275
Johan Hedberg272d90d2012-02-09 15:26:12 +02004276 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004277 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004278
4279 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004280 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004281}
4282
Brian Gix0df4c182011-11-16 13:53:13 -08004283static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004284 u8 link_type, u8 addr_type, u8 status,
4285 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004286{
4287 struct pending_cmd *cmd;
4288 struct mgmt_rp_user_confirm_reply rp;
4289 int err;
4290
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004291 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004292 if (!cmd)
4293 return -ENOENT;
4294
Johan Hedberg272d90d2012-02-09 15:26:12 +02004295 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004296 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004297 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004298 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004299
Johan Hedberga664b5b2011-02-19 12:06:02 -03004300 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004301
4302 return err;
4303}
4304
Johan Hedberg744cf192011-11-08 20:40:14 +02004305int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004306 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004307{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004308 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004309 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004310}
4311
Johan Hedberg272d90d2012-02-09 15:26:12 +02004312int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004313 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004314{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004315 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004316 status,
4317 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004318}
Johan Hedberg2a611692011-02-19 12:06:00 -03004319
Brian Gix604086b2011-11-23 08:28:33 -08004320int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004321 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004322{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004323 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004324 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004325}
4326
Johan Hedberg272d90d2012-02-09 15:26:12 +02004327int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004328 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004329{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004330 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004331 status,
4332 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004333}
4334
Johan Hedberg92a25252012-09-06 18:39:26 +03004335int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4336 u8 link_type, u8 addr_type, u32 passkey,
4337 u8 entered)
4338{
4339 struct mgmt_ev_passkey_notify ev;
4340
4341 BT_DBG("%s", hdev->name);
4342
4343 bacpy(&ev.addr.bdaddr, bdaddr);
4344 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4345 ev.passkey = __cpu_to_le32(passkey);
4346 ev.entered = entered;
4347
4348 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4349}
4350
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004351int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004352 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004353{
4354 struct mgmt_ev_auth_failed ev;
4355
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004356 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004357 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004358 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004359
Johan Hedberg744cf192011-11-08 20:40:14 +02004360 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004361}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004362
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004363int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4364{
4365 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004366 bool changed = false;
4367 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004368
4369 if (status) {
4370 u8 mgmt_err = mgmt_status(status);
4371 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004372 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004373 return 0;
4374 }
4375
Johan Hedberg47990ea2012-02-22 11:58:37 +02004376 if (test_bit(HCI_AUTH, &hdev->flags)) {
4377 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4378 changed = true;
4379 } else {
4380 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4381 changed = true;
4382 }
4383
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004384 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004385 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004386
Johan Hedberg47990ea2012-02-22 11:58:37 +02004387 if (changed)
4388 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004389
4390 if (match.sk)
4391 sock_put(match.sk);
4392
4393 return err;
4394}
4395
Johan Hedberg890ea892013-03-15 17:06:52 -05004396static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004397{
Johan Hedberg890ea892013-03-15 17:06:52 -05004398 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004399 struct hci_cp_write_eir cp;
4400
Johan Hedberg976eb202012-10-24 21:12:01 +03004401 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004402 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004403
Johan Hedbergc80da272012-02-22 15:38:48 +02004404 memset(hdev->eir, 0, sizeof(hdev->eir));
4405
Johan Hedbergcacaf522012-02-21 00:52:42 +02004406 memset(&cp, 0, sizeof(cp));
4407
Johan Hedberg890ea892013-03-15 17:06:52 -05004408 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004409}
4410
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004411int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004412{
4413 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004414 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004415 bool changed = false;
4416 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004417
4418 if (status) {
4419 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004420
4421 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004422 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004423 err = new_settings(hdev, NULL);
4424
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004425 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4426 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004427
4428 return err;
4429 }
4430
4431 if (enable) {
4432 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4433 changed = true;
4434 } else {
4435 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4436 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004437 }
4438
4439 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4440
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004441 if (changed)
4442 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004443
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004444 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004445 sock_put(match.sk);
4446
Johan Hedberg890ea892013-03-15 17:06:52 -05004447 hci_req_init(&req, hdev);
4448
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004449 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004450 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004451 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004452 clear_eir(&req);
4453
4454 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004455
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004456 return err;
4457}
4458
Johan Hedberg92da6092013-03-15 17:06:55 -05004459static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004460{
4461 struct cmd_lookup *match = data;
4462
Johan Hedberg90e70452012-02-23 23:09:40 +02004463 if (match->sk == NULL) {
4464 match->sk = cmd->sk;
4465 sock_hold(match->sk);
4466 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004467}
4468
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004469int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004470 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004471{
Johan Hedberg90e70452012-02-23 23:09:40 +02004472 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4473 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004474
Johan Hedberg92da6092013-03-15 17:06:55 -05004475 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4476 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4477 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004478
4479 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004480 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4481 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004482
4483 if (match.sk)
4484 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004485
4486 return err;
4487}
4488
Johan Hedberg744cf192011-11-08 20:40:14 +02004489int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004490{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004491 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004492 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004493
Johan Hedberg13928972013-03-15 17:07:00 -05004494 if (status)
4495 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004496
4497 memset(&ev, 0, sizeof(ev));
4498 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004499 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004500
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004501 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004502 if (!cmd) {
4503 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004504
Johan Hedberg13928972013-03-15 17:07:00 -05004505 /* If this is a HCI command related to powering on the
4506 * HCI dev don't send any mgmt signals.
4507 */
4508 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4509 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004510 }
4511
Johan Hedberg13928972013-03-15 17:07:00 -05004512 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4513 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004514}
Szymon Jancc35938b2011-03-22 13:12:21 +01004515
Johan Hedberg744cf192011-11-08 20:40:14 +02004516int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004517 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004518{
4519 struct pending_cmd *cmd;
4520 int err;
4521
Johan Hedberg744cf192011-11-08 20:40:14 +02004522 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004523
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004524 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004525 if (!cmd)
4526 return -ENOENT;
4527
4528 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004529 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4530 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004531 } else {
4532 struct mgmt_rp_read_local_oob_data rp;
4533
4534 memcpy(rp.hash, hash, sizeof(rp.hash));
4535 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4536
Johan Hedberg744cf192011-11-08 20:40:14 +02004537 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004538 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4539 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004540 }
4541
4542 mgmt_pending_remove(cmd);
4543
4544 return err;
4545}
Johan Hedberge17acd42011-03-30 23:57:16 +03004546
Johan Hedberg48264f02011-11-09 13:58:58 +02004547int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004548 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4549 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004550{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004551 char buf[512];
4552 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004553 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004554
Andre Guedes12602d02013-04-30 15:29:40 -03004555 if (!hci_discovery_active(hdev))
4556 return -EPERM;
4557
Johan Hedberg1dc06092012-01-15 21:01:23 +02004558 /* Leave 5 bytes for a potential CoD field */
4559 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004560 return -EINVAL;
4561
Johan Hedberg1dc06092012-01-15 21:01:23 +02004562 memset(buf, 0, sizeof(buf));
4563
Johan Hedberge319d2e2012-01-15 19:51:59 +02004564 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004565 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004566 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004567 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304568 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004569 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304570 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004571
Johan Hedberg1dc06092012-01-15 21:01:23 +02004572 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004573 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004574
Johan Hedberg1dc06092012-01-15 21:01:23 +02004575 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4576 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004577 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004578
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004579 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004580 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004581
Johan Hedberge319d2e2012-01-15 19:51:59 +02004582 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004583}
Johan Hedberga88a9652011-03-30 13:18:12 +03004584
Johan Hedbergb644ba32012-01-17 21:48:47 +02004585int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004586 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004587{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004588 struct mgmt_ev_device_found *ev;
4589 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4590 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004591
Johan Hedbergb644ba32012-01-17 21:48:47 +02004592 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004593
Johan Hedbergb644ba32012-01-17 21:48:47 +02004594 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004595
Johan Hedbergb644ba32012-01-17 21:48:47 +02004596 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004597 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004598 ev->rssi = rssi;
4599
4600 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004601 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004602
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004603 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004604
Johan Hedberg053c7e02012-02-04 00:06:00 +02004605 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004606 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004607}
Johan Hedberg314b2382011-04-27 10:29:57 -04004608
Johan Hedberg744cf192011-11-08 20:40:14 +02004609int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004610{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004611 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004612 struct pending_cmd *cmd;
4613
Andre Guedes343fb142011-11-22 17:14:19 -03004614 BT_DBG("%s discovering %u", hdev->name, discovering);
4615
Johan Hedberg164a6e72011-11-01 17:06:44 +02004616 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004617 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004618 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004619 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004620
4621 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004622 u8 type = hdev->discovery.type;
4623
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004624 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4625 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004626 mgmt_pending_remove(cmd);
4627 }
4628
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004629 memset(&ev, 0, sizeof(ev));
4630 ev.type = hdev->discovery.type;
4631 ev.discovering = discovering;
4632
4633 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004634}
Antti Julku5e762442011-08-25 16:48:02 +03004635
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004636int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004637{
4638 struct pending_cmd *cmd;
4639 struct mgmt_ev_device_blocked ev;
4640
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004641 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004642
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004643 bacpy(&ev.addr.bdaddr, bdaddr);
4644 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004645
Johan Hedberg744cf192011-11-08 20:40:14 +02004646 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004647 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004648}
4649
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004650int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004651{
4652 struct pending_cmd *cmd;
4653 struct mgmt_ev_device_unblocked ev;
4654
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004655 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004656
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004657 bacpy(&ev.addr.bdaddr, bdaddr);
4658 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004659
Johan Hedberg744cf192011-11-08 20:40:14 +02004660 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004661 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004662}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004663
4664static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4665{
4666 BT_DBG("%s status %u", hdev->name, status);
4667
4668 /* Clear the advertising mgmt setting if we failed to re-enable it */
4669 if (status) {
4670 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
4671 mgmt_new_settings(hdev);
4672 }
4673}
4674
4675void mgmt_reenable_advertising(struct hci_dev *hdev)
4676{
4677 struct hci_request req;
4678
4679 if (hdev->conn_hash.le_num)
4680 return;
4681
4682 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4683 return;
4684
4685 hci_req_init(&req, hdev);
4686 enable_advertising(&req);
4687
4688 /* If this fails we have no option but to let user space know
4689 * that we've disabled advertising.
4690 */
4691 if (hci_req_run(&req, adv_enable_complete) < 0) {
4692 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
4693 mgmt_new_settings(hdev);
4694 }
4695}