blob: 16125ff918f10991f7633921f2d4cbb03861c8f1 [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 Hedbergeeca6f82013-09-25 13:26:09 +0300428 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
429 settings |= MGMT_SETTING_ADVERTISING;
430
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200431 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200432}
433
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300434#define PNP_INFO_SVCLASS_ID 0x1200
435
Johan Hedberg213202e2013-01-27 00:31:33 +0200436static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
437{
438 u8 *ptr = data, *uuids_start = NULL;
439 struct bt_uuid *uuid;
440
441 if (len < 4)
442 return ptr;
443
444 list_for_each_entry(uuid, &hdev->uuids, list) {
445 u16 uuid16;
446
447 if (uuid->size != 16)
448 continue;
449
450 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
451 if (uuid16 < 0x1100)
452 continue;
453
454 if (uuid16 == PNP_INFO_SVCLASS_ID)
455 continue;
456
457 if (!uuids_start) {
458 uuids_start = ptr;
459 uuids_start[0] = 1;
460 uuids_start[1] = EIR_UUID16_ALL;
461 ptr += 2;
462 }
463
464 /* Stop if not enough space to put next UUID */
465 if ((ptr - data) + sizeof(u16) > len) {
466 uuids_start[1] = EIR_UUID16_SOME;
467 break;
468 }
469
470 *ptr++ = (uuid16 & 0x00ff);
471 *ptr++ = (uuid16 & 0xff00) >> 8;
472 uuids_start[0] += sizeof(uuid16);
473 }
474
475 return ptr;
476}
477
Johan Hedbergcdf19632013-01-27 00:31:34 +0200478static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
479{
480 u8 *ptr = data, *uuids_start = NULL;
481 struct bt_uuid *uuid;
482
483 if (len < 6)
484 return ptr;
485
486 list_for_each_entry(uuid, &hdev->uuids, list) {
487 if (uuid->size != 32)
488 continue;
489
490 if (!uuids_start) {
491 uuids_start = ptr;
492 uuids_start[0] = 1;
493 uuids_start[1] = EIR_UUID32_ALL;
494 ptr += 2;
495 }
496
497 /* Stop if not enough space to put next UUID */
498 if ((ptr - data) + sizeof(u32) > len) {
499 uuids_start[1] = EIR_UUID32_SOME;
500 break;
501 }
502
503 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
504 ptr += sizeof(u32);
505 uuids_start[0] += sizeof(u32);
506 }
507
508 return ptr;
509}
510
Johan Hedbergc00d5752013-01-27 00:31:35 +0200511static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
512{
513 u8 *ptr = data, *uuids_start = NULL;
514 struct bt_uuid *uuid;
515
516 if (len < 18)
517 return ptr;
518
519 list_for_each_entry(uuid, &hdev->uuids, list) {
520 if (uuid->size != 128)
521 continue;
522
523 if (!uuids_start) {
524 uuids_start = ptr;
525 uuids_start[0] = 1;
526 uuids_start[1] = EIR_UUID128_ALL;
527 ptr += 2;
528 }
529
530 /* Stop if not enough space to put next UUID */
531 if ((ptr - data) + 16 > len) {
532 uuids_start[1] = EIR_UUID128_SOME;
533 break;
534 }
535
536 memcpy(ptr, uuid->uuid, 16);
537 ptr += 16;
538 uuids_start[0] += 16;
539 }
540
541 return ptr;
542}
543
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300544static void create_eir(struct hci_dev *hdev, u8 *data)
545{
546 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547 size_t name_len;
548
549 name_len = strlen(hdev->dev_name);
550
551 if (name_len > 0) {
552 /* EIR Data type */
553 if (name_len > 48) {
554 name_len = 48;
555 ptr[1] = EIR_NAME_SHORT;
556 } else
557 ptr[1] = EIR_NAME_COMPLETE;
558
559 /* EIR Data length */
560 ptr[0] = name_len + 1;
561
562 memcpy(ptr + 2, hdev->dev_name, name_len);
563
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 ptr += (name_len + 2);
565 }
566
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100567 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700568 ptr[0] = 2;
569 ptr[1] = EIR_TX_POWER;
570 ptr[2] = (u8) hdev->inq_tx_power;
571
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700572 ptr += 3;
573 }
574
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700575 if (hdev->devid_source > 0) {
576 ptr[0] = 9;
577 ptr[1] = EIR_DEVICE_ID;
578
579 put_unaligned_le16(hdev->devid_source, ptr + 2);
580 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
581 put_unaligned_le16(hdev->devid_product, ptr + 6);
582 put_unaligned_le16(hdev->devid_version, ptr + 8);
583
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700584 ptr += 10;
585 }
586
Johan Hedberg213202e2013-01-27 00:31:33 +0200587 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200588 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200589 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300590}
591
Johan Hedberg890ea892013-03-15 17:06:52 -0500592static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300593{
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595 struct hci_cp_write_eir cp;
596
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200597 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500598 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200599
Johan Hedberg976eb202012-10-24 21:12:01 +0300600 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500601 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300602
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200603 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500604 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300605
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200606 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500607 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608
609 memset(&cp, 0, sizeof(cp));
610
611 create_eir(hdev, cp.data);
612
613 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500614 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300615
616 memcpy(hdev->eir, cp.data, sizeof(cp.data));
617
Johan Hedberg890ea892013-03-15 17:06:52 -0500618 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300619}
620
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621static u8 get_service_classes(struct hci_dev *hdev)
622{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300623 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624 u8 val = 0;
625
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300626 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628
629 return val;
630}
631
Johan Hedberg890ea892013-03-15 17:06:52 -0500632static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200633{
Johan Hedberg890ea892013-03-15 17:06:52 -0500634 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200635 u8 cod[3];
636
637 BT_DBG("%s", hdev->name);
638
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200639 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500640 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200641
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200642 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500643 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200644
645 cod[0] = hdev->minor_class;
646 cod[1] = hdev->major_class;
647 cod[2] = get_service_classes(hdev);
648
649 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500650 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200651
Johan Hedberg890ea892013-03-15 17:06:52 -0500652 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200653}
654
Johan Hedberg7d785252011-12-15 00:47:39 +0200655static void service_cache_off(struct work_struct *work)
656{
657 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300658 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500659 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200660
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200661 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200662 return;
663
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 hci_req_init(&req, hdev);
665
Johan Hedberg7d785252011-12-15 00:47:39 +0200666 hci_dev_lock(hdev);
667
Johan Hedberg890ea892013-03-15 17:06:52 -0500668 update_eir(&req);
669 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200670
671 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500672
673 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200674}
675
Johan Hedberg6a919082012-02-28 06:17:26 +0200676static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200677{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200678 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200679 return;
680
Johan Hedberg4f87da82012-03-02 19:55:56 +0200681 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200682
Johan Hedberg4f87da82012-03-02 19:55:56 +0200683 /* Non-mgmt controlled devices get this bit set
684 * implicitly so that pairing works for them, however
685 * for mgmt we require user-space to explicitly enable
686 * it
687 */
688 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200689}
690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200691static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200693{
694 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200696 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200697
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300698 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200699
Johan Hedberg03811012010-12-08 00:21:06 +0200700 memset(&rp, 0, sizeof(rp));
701
Johan Hedberg03811012010-12-08 00:21:06 +0200702 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200703
704 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200705 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200706
707 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
708 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
709
710 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200711
712 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200713 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300715 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200716
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200717 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300718 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200719}
720
721static void mgmt_pending_free(struct pending_cmd *cmd)
722{
723 sock_put(cmd->sk);
724 kfree(cmd->param);
725 kfree(cmd);
726}
727
728static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300729 struct hci_dev *hdev, void *data,
730 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200731{
732 struct pending_cmd *cmd;
733
Andre Guedes12b94562012-06-07 19:05:45 -0300734 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200735 if (!cmd)
736 return NULL;
737
738 cmd->opcode = opcode;
739 cmd->index = hdev->id;
740
Andre Guedes12b94562012-06-07 19:05:45 -0300741 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 if (!cmd->param) {
743 kfree(cmd);
744 return NULL;
745 }
746
747 if (data)
748 memcpy(cmd->param, data, len);
749
750 cmd->sk = sk;
751 sock_hold(sk);
752
753 list_add(&cmd->list, &hdev->mgmt_pending);
754
755 return cmd;
756}
757
758static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300759 void (*cb)(struct pending_cmd *cmd,
760 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300761 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200762{
Andre Guedesa3d09352013-02-01 11:21:30 -0300763 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Andre Guedesa3d09352013-02-01 11:21:30 -0300765 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200766 if (opcode > 0 && cmd->opcode != opcode)
767 continue;
768
769 cb(cmd, data);
770 }
771}
772
773static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
774{
775 struct pending_cmd *cmd;
776
777 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
778 if (cmd->opcode == opcode)
779 return cmd;
780 }
781
782 return NULL;
783}
784
785static void mgmt_pending_remove(struct pending_cmd *cmd)
786{
787 list_del(&cmd->list);
788 mgmt_pending_free(cmd);
789}
790
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200792{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200793 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200794
Johan Hedbergaee9b212012-02-18 15:07:59 +0200795 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200797}
798
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200799static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300800 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200801{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300802 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200803 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200804 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200806 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedberga7e80f22013-01-09 16:05:19 +0200808 if (cp->val != 0x00 && cp->val != 0x01)
809 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
810 MGMT_STATUS_INVALID_PARAMS);
811
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300812 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200813
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300814 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
815 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
816 MGMT_STATUS_BUSY);
817 goto failed;
818 }
819
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100820 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
821 cancel_delayed_work(&hdev->power_off);
822
823 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200824 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
825 data, len);
826 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100827 goto failed;
828 }
829 }
830
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200831 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200832 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200833 goto failed;
834 }
835
Johan Hedberg03811012010-12-08 00:21:06 +0200836 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
837 if (!cmd) {
838 err = -ENOMEM;
839 goto failed;
840 }
841
842 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200843 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200844 else
Johan Hedberg19202572013-01-14 22:33:51 +0200845 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200846
847 err = 0;
848
849failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300850 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200851 return err;
852}
853
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300854static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
855 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200856{
857 struct sk_buff *skb;
858 struct mgmt_hdr *hdr;
859
Andre Guedes790eff42012-06-07 19:05:46 -0300860 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200861 if (!skb)
862 return -ENOMEM;
863
864 hdr = (void *) skb_put(skb, sizeof(*hdr));
865 hdr->opcode = cpu_to_le16(event);
866 if (hdev)
867 hdr->index = cpu_to_le16(hdev->id);
868 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530869 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200870 hdr->len = cpu_to_le16(data_len);
871
872 if (data)
873 memcpy(skb_put(skb, data_len), data, data_len);
874
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100875 /* Time stamp */
876 __net_timestamp(skb);
877
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200878 hci_send_to_control(skb, skip_sk);
879 kfree_skb(skb);
880
881 return 0;
882}
883
884static int new_settings(struct hci_dev *hdev, struct sock *skip)
885{
886 __le32 ev;
887
888 ev = cpu_to_le32(get_current_settings(hdev));
889
890 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
891}
892
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300893struct cmd_lookup {
894 struct sock *sk;
895 struct hci_dev *hdev;
896 u8 mgmt_status;
897};
898
899static void settings_rsp(struct pending_cmd *cmd, void *data)
900{
901 struct cmd_lookup *match = data;
902
903 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
904
905 list_del(&cmd->list);
906
907 if (match->sk == NULL) {
908 match->sk = cmd->sk;
909 sock_hold(match->sk);
910 }
911
912 mgmt_pending_free(cmd);
913}
914
915static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
916{
917 u8 *status = data;
918
919 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
920 mgmt_pending_remove(cmd);
921}
922
Johan Hedberge6fe7982013-10-02 15:45:22 +0300923static u8 mgmt_bredr_support(struct hci_dev *hdev)
924{
925 if (!lmp_bredr_capable(hdev))
926 return MGMT_STATUS_NOT_SUPPORTED;
927 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
928 return MGMT_STATUS_REJECTED;
929 else
930 return MGMT_STATUS_SUCCESS;
931}
932
933static u8 mgmt_le_support(struct hci_dev *hdev)
934{
935 if (!lmp_le_capable(hdev))
936 return MGMT_STATUS_NOT_SUPPORTED;
937 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
938 return MGMT_STATUS_REJECTED;
939 else
940 return MGMT_STATUS_SUCCESS;
941}
942
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200943static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300944 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200945{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300946 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200947 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200948 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300949 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200950 int err;
951
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200952 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200953
Johan Hedberge6fe7982013-10-02 15:45:22 +0300954 status = mgmt_bredr_support(hdev);
955 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300956 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300957 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300958
Johan Hedberga7e80f22013-01-09 16:05:19 +0200959 if (cp->val != 0x00 && cp->val != 0x01)
960 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
961 MGMT_STATUS_INVALID_PARAMS);
962
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700963 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100964 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200965 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300966 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200967
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300968 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200969
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200971 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300972 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200973 goto failed;
974 }
975
976 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300977 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200978 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300979 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200980 goto failed;
981 }
982
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200983 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200984 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300985 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200986 goto failed;
987 }
988
989 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200990 bool changed = false;
991
992 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
993 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
994 changed = true;
995 }
996
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200997 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200998 if (err < 0)
999 goto failed;
1000
1001 if (changed)
1002 err = new_settings(hdev, sk);
1003
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001004 goto failed;
1005 }
1006
1007 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001008 if (hdev->discov_timeout > 0) {
1009 cancel_delayed_work(&hdev->discov_off);
1010 hdev->discov_timeout = 0;
1011 }
1012
1013 if (cp->val && timeout > 0) {
1014 hdev->discov_timeout = timeout;
1015 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1016 msecs_to_jiffies(hdev->discov_timeout * 1000));
1017 }
1018
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001019 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001020 goto failed;
1021 }
1022
1023 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1024 if (!cmd) {
1025 err = -ENOMEM;
1026 goto failed;
1027 }
1028
1029 scan = SCAN_PAGE;
1030
1031 if (cp->val)
1032 scan |= SCAN_INQUIRY;
1033 else
1034 cancel_delayed_work(&hdev->discov_off);
1035
1036 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1037 if (err < 0)
1038 mgmt_pending_remove(cmd);
1039
Johan Hedberg03811012010-12-08 00:21:06 +02001040 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001041 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001042
1043failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001044 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001045 return err;
1046}
1047
Johan Hedberg406d7802013-03-15 17:07:09 -05001048static void write_fast_connectable(struct hci_request *req, bool enable)
1049{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001050 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001051 struct hci_cp_write_page_scan_activity acp;
1052 u8 type;
1053
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001054 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1055 return;
1056
Johan Hedberg406d7802013-03-15 17:07:09 -05001057 if (enable) {
1058 type = PAGE_SCAN_TYPE_INTERLACED;
1059
1060 /* 160 msec page scan interval */
1061 acp.interval = __constant_cpu_to_le16(0x0100);
1062 } else {
1063 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1064
1065 /* default 1.28 sec page scan */
1066 acp.interval = __constant_cpu_to_le16(0x0800);
1067 }
1068
1069 acp.window = __constant_cpu_to_le16(0x0012);
1070
Johan Hedbergbd98b992013-03-15 17:07:13 -05001071 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1072 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1073 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1074 sizeof(acp), &acp);
1075
1076 if (hdev->page_scan_type != type)
1077 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001078}
1079
Johan Hedberg2b76f452013-03-15 17:07:04 -05001080static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1081{
1082 struct pending_cmd *cmd;
1083
1084 BT_DBG("status 0x%02x", status);
1085
1086 hci_dev_lock(hdev);
1087
1088 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1089 if (!cmd)
1090 goto unlock;
1091
1092 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1093
1094 mgmt_pending_remove(cmd);
1095
1096unlock:
1097 hci_dev_unlock(hdev);
1098}
1099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001100static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001101 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001102{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001103 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001104 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001105 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001106 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001107 int err;
1108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001110
Johan Hedberge6fe7982013-10-02 15:45:22 +03001111 status = mgmt_bredr_support(hdev);
1112 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001113 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001114 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001115
Johan Hedberga7e80f22013-01-09 16:05:19 +02001116 if (cp->val != 0x00 && cp->val != 0x01)
1117 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1118 MGMT_STATUS_INVALID_PARAMS);
1119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001120 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001121
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001122 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001123 bool changed = false;
1124
1125 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1126 changed = true;
1127
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001128 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001129 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001130 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001131 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1132 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1133 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001134
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001135 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001136 if (err < 0)
1137 goto failed;
1138
1139 if (changed)
1140 err = new_settings(hdev, sk);
1141
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001142 goto failed;
1143 }
1144
1145 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001146 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001149 goto failed;
1150 }
1151
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001152 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001153 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001154 goto failed;
1155 }
1156
1157 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1158 if (!cmd) {
1159 err = -ENOMEM;
1160 goto failed;
1161 }
1162
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001163 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001165 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166 scan = 0;
1167
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001168 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001169 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001170 cancel_delayed_work(&hdev->discov_off);
1171 }
1172
Johan Hedberg2b76f452013-03-15 17:07:04 -05001173 hci_req_init(&req, hdev);
1174
1175 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1176
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001177 /* If we're going from non-connectable to connectable or
1178 * vice-versa when fast connectable is enabled ensure that fast
1179 * connectable gets disabled. write_fast_connectable won't do
1180 * anything if the page scan parameters are already what they
1181 * should be.
1182 */
1183 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001184 write_fast_connectable(&req, false);
1185
Johan Hedberg2b76f452013-03-15 17:07:04 -05001186 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187 if (err < 0)
1188 mgmt_pending_remove(cmd);
1189
1190failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001191 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192 return err;
1193}
1194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001196 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001197{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001198 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001199 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001201 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202
Johan Hedberga7e80f22013-01-09 16:05:19 +02001203 if (cp->val != 0x00 && cp->val != 0x01)
1204 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1205 MGMT_STATUS_INVALID_PARAMS);
1206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001207 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001208
1209 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001210 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001212 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001214 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001215 if (err < 0)
1216 goto failed;
1217
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001218 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001219
1220failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001221 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001222 return err;
1223}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001224
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001225static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1226 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001227{
1228 struct mgmt_mode *cp = data;
1229 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001230 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001231 int err;
1232
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001233 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001234
Johan Hedberge6fe7982013-10-02 15:45:22 +03001235 status = mgmt_bredr_support(hdev);
1236 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001237 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001238 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001239
Johan Hedberga7e80f22013-01-09 16:05:19 +02001240 if (cp->val != 0x00 && cp->val != 0x01)
1241 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1242 MGMT_STATUS_INVALID_PARAMS);
1243
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001244 hci_dev_lock(hdev);
1245
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001246 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001247 bool changed = false;
1248
1249 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001250 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001251 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1252 changed = true;
1253 }
1254
1255 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1256 if (err < 0)
1257 goto failed;
1258
1259 if (changed)
1260 err = new_settings(hdev, sk);
1261
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001262 goto failed;
1263 }
1264
1265 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001266 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001267 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001268 goto failed;
1269 }
1270
1271 val = !!cp->val;
1272
1273 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1274 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1275 goto failed;
1276 }
1277
1278 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1279 if (!cmd) {
1280 err = -ENOMEM;
1281 goto failed;
1282 }
1283
1284 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1285 if (err < 0) {
1286 mgmt_pending_remove(cmd);
1287 goto failed;
1288 }
1289
1290failed:
1291 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001292 return err;
1293}
1294
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001295static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001296{
1297 struct mgmt_mode *cp = data;
1298 struct pending_cmd *cmd;
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001299 u8 val, status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001300 int err;
1301
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001302 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001303
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001304 status = mgmt_bredr_support(hdev);
1305 if (status)
1306 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1307
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001308 if (!lmp_ssp_capable(hdev))
1309 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1310 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001311
Johan Hedberga7e80f22013-01-09 16:05:19 +02001312 if (cp->val != 0x00 && cp->val != 0x01)
1313 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1314 MGMT_STATUS_INVALID_PARAMS);
1315
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001316 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001317
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001318 val = !!cp->val;
1319
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001320 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001321 bool changed = false;
1322
1323 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1324 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1325 changed = true;
1326 }
1327
1328 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1329 if (err < 0)
1330 goto failed;
1331
1332 if (changed)
1333 err = new_settings(hdev, sk);
1334
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001335 goto failed;
1336 }
1337
1338 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001339 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1340 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001341 goto failed;
1342 }
1343
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001344 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1345 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1346 goto failed;
1347 }
1348
1349 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1350 if (!cmd) {
1351 err = -ENOMEM;
1352 goto failed;
1353 }
1354
1355 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1356 if (err < 0) {
1357 mgmt_pending_remove(cmd);
1358 goto failed;
1359 }
1360
1361failed:
1362 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001363 return err;
1364}
1365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001366static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001367{
1368 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001369 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001370 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001371 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001373 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001374
Johan Hedberge6fe7982013-10-02 15:45:22 +03001375 status = mgmt_bredr_support(hdev);
1376 if (status)
1377 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001378
Johan Hedberga7e80f22013-01-09 16:05:19 +02001379 if (cp->val != 0x00 && cp->val != 0x01)
1380 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1381 MGMT_STATUS_INVALID_PARAMS);
1382
Marcel Holtmannee392692013-10-01 22:59:23 -07001383 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001384
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001385 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001386 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001387 } else {
1388 if (hdev_is_powered(hdev)) {
1389 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1390 MGMT_STATUS_REJECTED);
1391 goto unlock;
1392 }
1393
Marcel Holtmannee392692013-10-01 22:59:23 -07001394 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001395 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001396
1397 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1398 if (err < 0)
1399 goto unlock;
1400
1401 if (changed)
1402 err = new_settings(hdev, sk);
1403
1404unlock:
1405 hci_dev_unlock(hdev);
1406 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001407}
1408
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001409static void le_enable_complete(struct hci_dev *hdev, u8 status)
1410{
1411 struct cmd_lookup match = { NULL, hdev };
1412
1413 if (status) {
1414 u8 mgmt_err = mgmt_status(status);
1415
1416 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1417 &mgmt_err);
1418 return;
1419 }
1420
1421 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1422
1423 new_settings(hdev, match.sk);
1424
1425 if (match.sk)
1426 sock_put(match.sk);
1427}
1428
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001429static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001430{
1431 struct mgmt_mode *cp = data;
1432 struct hci_cp_write_le_host_supported hci_cp;
1433 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001434 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001435 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001436 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001437
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001438 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001439
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001440 if (!lmp_le_capable(hdev))
1441 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1442 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001443
Johan Hedberga7e80f22013-01-09 16:05:19 +02001444 if (cp->val != 0x00 && cp->val != 0x01)
1445 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1446 MGMT_STATUS_INVALID_PARAMS);
1447
Johan Hedbergc73eee92013-04-19 18:35:21 +03001448 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001449 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001450 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1451 MGMT_STATUS_REJECTED);
1452
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001453 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001454
1455 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001456 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001457
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001458 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001459 bool changed = false;
1460
1461 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1462 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1463 changed = true;
1464 }
1465
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001466 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1467 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1468 changed = true;
1469 }
1470
Johan Hedberg06199cf2012-02-22 16:37:11 +02001471 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1472 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001473 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001474
1475 if (changed)
1476 err = new_settings(hdev, sk);
1477
Johan Hedberg1de028c2012-02-29 19:55:35 -08001478 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001479 }
1480
Johan Hedberg4375f102013-09-25 13:26:10 +03001481 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1482 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001483 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001484 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001485 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001486 }
1487
1488 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1489 if (!cmd) {
1490 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001491 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001492 }
1493
1494 memset(&hci_cp, 0, sizeof(hci_cp));
1495
1496 if (val) {
1497 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001498 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001499 }
1500
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001501 hci_req_init(&req, hdev);
1502
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001503 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1504 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1505
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001506 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1507 &hci_cp);
1508
1509 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301510 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001511 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001512
Johan Hedberg1de028c2012-02-29 19:55:35 -08001513unlock:
1514 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001515 return err;
1516}
1517
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001518/* This is a helper function to test for pending mgmt commands that can
1519 * cause CoD or EIR HCI commands. We can only allow one such pending
1520 * mgmt command at a time since otherwise we cannot easily track what
1521 * the current values are, will be, and based on that calculate if a new
1522 * HCI command needs to be sent and if yes with what value.
1523 */
1524static bool pending_eir_or_class(struct hci_dev *hdev)
1525{
1526 struct pending_cmd *cmd;
1527
1528 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1529 switch (cmd->opcode) {
1530 case MGMT_OP_ADD_UUID:
1531 case MGMT_OP_REMOVE_UUID:
1532 case MGMT_OP_SET_DEV_CLASS:
1533 case MGMT_OP_SET_POWERED:
1534 return true;
1535 }
1536 }
1537
1538 return false;
1539}
1540
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001541static const u8 bluetooth_base_uuid[] = {
1542 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1543 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1544};
1545
1546static u8 get_uuid_size(const u8 *uuid)
1547{
1548 u32 val;
1549
1550 if (memcmp(uuid, bluetooth_base_uuid, 12))
1551 return 128;
1552
1553 val = get_unaligned_le32(&uuid[12]);
1554 if (val > 0xffff)
1555 return 32;
1556
1557 return 16;
1558}
1559
Johan Hedberg92da6092013-03-15 17:06:55 -05001560static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1561{
1562 struct pending_cmd *cmd;
1563
1564 hci_dev_lock(hdev);
1565
1566 cmd = mgmt_pending_find(mgmt_op, hdev);
1567 if (!cmd)
1568 goto unlock;
1569
1570 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1571 hdev->dev_class, 3);
1572
1573 mgmt_pending_remove(cmd);
1574
1575unlock:
1576 hci_dev_unlock(hdev);
1577}
1578
1579static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1580{
1581 BT_DBG("status 0x%02x", status);
1582
1583 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1584}
1585
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001586static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001587{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001588 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001589 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001590 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001591 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001592 int err;
1593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001594 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001595
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001596 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001597
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001598 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001599 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001600 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001601 goto failed;
1602 }
1603
Andre Guedes92c4c202012-06-07 19:05:44 -03001604 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001605 if (!uuid) {
1606 err = -ENOMEM;
1607 goto failed;
1608 }
1609
1610 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001611 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001612 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001613
Johan Hedbergde66aa62013-01-27 00:31:27 +02001614 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001615
Johan Hedberg890ea892013-03-15 17:06:52 -05001616 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001617
Johan Hedberg890ea892013-03-15 17:06:52 -05001618 update_class(&req);
1619 update_eir(&req);
1620
Johan Hedberg92da6092013-03-15 17:06:55 -05001621 err = hci_req_run(&req, add_uuid_complete);
1622 if (err < 0) {
1623 if (err != -ENODATA)
1624 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001626 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001627 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001628 goto failed;
1629 }
1630
1631 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001632 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001633 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001634 goto failed;
1635 }
1636
1637 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001638
1639failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001640 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001641 return err;
1642}
1643
Johan Hedberg24b78d02012-02-23 23:24:30 +02001644static bool enable_service_cache(struct hci_dev *hdev)
1645{
1646 if (!hdev_is_powered(hdev))
1647 return false;
1648
1649 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001650 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1651 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001652 return true;
1653 }
1654
1655 return false;
1656}
1657
Johan Hedberg92da6092013-03-15 17:06:55 -05001658static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1659{
1660 BT_DBG("status 0x%02x", status);
1661
1662 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1663}
1664
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001665static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001666 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001667{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001668 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001669 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001670 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001671 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 -05001672 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001673 int err, found;
1674
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001675 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001676
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001677 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001678
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001679 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001680 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001681 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001682 goto unlock;
1683 }
1684
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001685 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1686 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001687
Johan Hedberg24b78d02012-02-23 23:24:30 +02001688 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001689 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001690 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001691 goto unlock;
1692 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001693
Johan Hedberg9246a862012-02-23 21:33:16 +02001694 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001695 }
1696
1697 found = 0;
1698
Johan Hedberg056341c2013-01-27 00:31:30 +02001699 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001700 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1701 continue;
1702
1703 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001704 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001705 found++;
1706 }
1707
1708 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001709 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001710 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001711 goto unlock;
1712 }
1713
Johan Hedberg9246a862012-02-23 21:33:16 +02001714update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001715 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001716
Johan Hedberg890ea892013-03-15 17:06:52 -05001717 update_class(&req);
1718 update_eir(&req);
1719
Johan Hedberg92da6092013-03-15 17:06:55 -05001720 err = hci_req_run(&req, remove_uuid_complete);
1721 if (err < 0) {
1722 if (err != -ENODATA)
1723 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001724
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001725 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001726 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001727 goto unlock;
1728 }
1729
1730 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001731 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001732 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001733 goto unlock;
1734 }
1735
1736 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001737
1738unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001739 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001740 return err;
1741}
1742
Johan Hedberg92da6092013-03-15 17:06:55 -05001743static void set_class_complete(struct hci_dev *hdev, u8 status)
1744{
1745 BT_DBG("status 0x%02x", status);
1746
1747 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1748}
1749
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001750static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001751 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001752{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001753 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001754 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001755 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001756 int err;
1757
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001758 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001759
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001760 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001761 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1762 MGMT_STATUS_NOT_SUPPORTED);
1763
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001764 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001765
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001766 if (pending_eir_or_class(hdev)) {
1767 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1768 MGMT_STATUS_BUSY);
1769 goto unlock;
1770 }
1771
1772 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1773 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1774 MGMT_STATUS_INVALID_PARAMS);
1775 goto unlock;
1776 }
1777
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001778 hdev->major_class = cp->major;
1779 hdev->minor_class = cp->minor;
1780
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001781 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001782 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001783 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001784 goto unlock;
1785 }
1786
Johan Hedberg890ea892013-03-15 17:06:52 -05001787 hci_req_init(&req, hdev);
1788
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001789 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001790 hci_dev_unlock(hdev);
1791 cancel_delayed_work_sync(&hdev->service_cache);
1792 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001793 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001794 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001795
Johan Hedberg890ea892013-03-15 17:06:52 -05001796 update_class(&req);
1797
Johan Hedberg92da6092013-03-15 17:06:55 -05001798 err = hci_req_run(&req, set_class_complete);
1799 if (err < 0) {
1800 if (err != -ENODATA)
1801 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001802
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001803 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001804 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001805 goto unlock;
1806 }
1807
1808 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001809 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001810 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001811 goto unlock;
1812 }
1813
1814 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001815
Johan Hedbergb5235a62012-02-21 14:32:24 +02001816unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001817 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001818 return err;
1819}
1820
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001821static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001822 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001823{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001824 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001825 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001826 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001827
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001828 BT_DBG("request for %s", hdev->name);
1829
1830 if (!lmp_bredr_capable(hdev))
1831 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1832 MGMT_STATUS_NOT_SUPPORTED);
1833
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001834 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001835
Johan Hedberg86742e12011-11-07 23:13:38 +02001836 expected_len = sizeof(*cp) + key_count *
1837 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001838 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001839 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001840 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001843 }
1844
Johan Hedberg4ae143012013-01-20 14:27:13 +02001845 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1846 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1847 MGMT_STATUS_INVALID_PARAMS);
1848
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001849 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001850 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001851
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001852 for (i = 0; i < key_count; i++) {
1853 struct mgmt_link_key_info *key = &cp->keys[i];
1854
1855 if (key->addr.type != BDADDR_BREDR)
1856 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1857 MGMT_STATUS_INVALID_PARAMS);
1858 }
1859
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001860 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001861
1862 hci_link_keys_clear(hdev);
1863
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001864 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001865 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001866 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001867 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001868
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001869 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001870 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001871
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001872 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001873 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001874 }
1875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001876 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001877
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001878 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001880 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001881}
1882
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001883static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001884 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001885{
1886 struct mgmt_ev_device_unpaired ev;
1887
1888 bacpy(&ev.addr.bdaddr, bdaddr);
1889 ev.addr.type = addr_type;
1890
1891 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001892 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001893}
1894
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001895static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001896 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001897{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001898 struct mgmt_cp_unpair_device *cp = data;
1899 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001900 struct hci_cp_disconnect dc;
1901 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001902 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001903 int err;
1904
Johan Hedberga8a1d192011-11-10 15:54:38 +02001905 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001906 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1907 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001908
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001909 if (!bdaddr_type_is_valid(cp->addr.type))
1910 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1911 MGMT_STATUS_INVALID_PARAMS,
1912 &rp, sizeof(rp));
1913
Johan Hedberg118da702013-01-20 14:27:20 +02001914 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1915 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1916 MGMT_STATUS_INVALID_PARAMS,
1917 &rp, sizeof(rp));
1918
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001919 hci_dev_lock(hdev);
1920
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001921 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001922 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001923 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001924 goto unlock;
1925 }
1926
Andre Guedes591f47f2012-04-24 21:02:49 -03001927 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001928 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1929 else
1930 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001931
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001932 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001933 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001934 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001935 goto unlock;
1936 }
1937
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001938 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001939 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001940 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001941 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001942 else
1943 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001944 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001945 } else {
1946 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001947 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001948
Johan Hedberga8a1d192011-11-10 15:54:38 +02001949 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001950 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001951 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001952 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001953 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001954 }
1955
Johan Hedberg124f6e32012-02-09 13:50:12 +02001956 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001957 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001958 if (!cmd) {
1959 err = -ENOMEM;
1960 goto unlock;
1961 }
1962
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001963 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001964 dc.reason = 0x13; /* Remote User Terminated Connection */
1965 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1966 if (err < 0)
1967 mgmt_pending_remove(cmd);
1968
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001969unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001970 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001971 return err;
1972}
1973
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001974static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001975 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001976{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001977 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001978 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001979 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001980 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001981 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001982 int err;
1983
1984 BT_DBG("");
1985
Johan Hedberg06a63b12013-01-20 14:27:21 +02001986 memset(&rp, 0, sizeof(rp));
1987 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1988 rp.addr.type = cp->addr.type;
1989
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001990 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001991 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1992 MGMT_STATUS_INVALID_PARAMS,
1993 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001994
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001995 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001996
1997 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001998 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1999 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002000 goto failed;
2001 }
2002
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002003 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002004 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2005 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002006 goto failed;
2007 }
2008
Andre Guedes591f47f2012-04-24 21:02:49 -03002009 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002010 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2011 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002012 else
2013 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002014
Vishal Agarwalf9607272012-06-13 05:32:43 +05302015 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002016 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2017 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002018 goto failed;
2019 }
2020
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002021 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002022 if (!cmd) {
2023 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002024 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002025 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002026
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002027 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002028 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002029
2030 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2031 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002032 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002033
2034failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002035 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002036 return err;
2037}
2038
Andre Guedes57c14772012-04-24 21:02:50 -03002039static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002040{
2041 switch (link_type) {
2042 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002043 switch (addr_type) {
2044 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002045 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002046
Johan Hedberg48264f02011-11-09 13:58:58 +02002047 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002048 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002049 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002050 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002051
Johan Hedberg4c659c32011-11-07 23:13:39 +02002052 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002053 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002054 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002055 }
2056}
2057
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002058static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2059 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002060{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002061 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002062 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002063 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002064 int err;
2065 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002066
2067 BT_DBG("");
2068
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002069 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002070
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002071 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002072 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002073 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002074 goto unlock;
2075 }
2076
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002077 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002078 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2079 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002080 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002081 }
2082
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002083 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002084 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002085 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002086 err = -ENOMEM;
2087 goto unlock;
2088 }
2089
Johan Hedberg2784eb42011-01-21 13:56:35 +02002090 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002091 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002092 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2093 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002094 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002095 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002096 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002097 continue;
2098 i++;
2099 }
2100
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002101 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002102
Johan Hedberg4c659c32011-11-07 23:13:39 +02002103 /* Recalculate length in case of filtered SCO connections, etc */
2104 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002105
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002106 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002107 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002108
Johan Hedberga38528f2011-01-22 06:46:43 +02002109 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002110
2111unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002113 return err;
2114}
2115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002117 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002118{
2119 struct pending_cmd *cmd;
2120 int err;
2121
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002122 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002123 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002124 if (!cmd)
2125 return -ENOMEM;
2126
Johan Hedbergd8457692012-02-17 14:24:57 +02002127 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002128 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002129 if (err < 0)
2130 mgmt_pending_remove(cmd);
2131
2132 return err;
2133}
2134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002135static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002136 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002137{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002138 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002139 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002141 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142 int err;
2143
2144 BT_DBG("");
2145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002146 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002147
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002148 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002149 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002150 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002151 goto failed;
2152 }
2153
Johan Hedbergd8457692012-02-17 14:24:57 +02002154 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002155 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002156 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002158 goto failed;
2159 }
2160
2161 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002162 struct mgmt_cp_pin_code_neg_reply ncp;
2163
2164 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002165
2166 BT_ERR("PIN code is not 16 bytes long");
2167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002168 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002169 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002170 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002171 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002172
2173 goto failed;
2174 }
2175
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002176 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002177 if (!cmd) {
2178 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002180 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002181
Johan Hedbergd8457692012-02-17 14:24:57 +02002182 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002183 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002184 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185
2186 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2187 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002188 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002189
2190failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002191 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002192 return err;
2193}
2194
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002195static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2196 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002197{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002198 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002199
2200 BT_DBG("");
2201
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002202 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002203
2204 hdev->io_capability = cp->io_capability;
2205
2206 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002207 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002208
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002209 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002210
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002211 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2212 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002213}
2214
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002215static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002216{
2217 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002218 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002219
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002220 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002221 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2222 continue;
2223
Johan Hedberge9a416b2011-02-19 12:05:56 -03002224 if (cmd->user_data != conn)
2225 continue;
2226
2227 return cmd;
2228 }
2229
2230 return NULL;
2231}
2232
2233static void pairing_complete(struct pending_cmd *cmd, u8 status)
2234{
2235 struct mgmt_rp_pair_device rp;
2236 struct hci_conn *conn = cmd->user_data;
2237
Johan Hedbergba4e5642011-11-11 00:07:34 +02002238 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002239 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002240
Johan Hedbergaee9b212012-02-18 15:07:59 +02002241 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002242 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002243
2244 /* So we don't get further callbacks for this connection */
2245 conn->connect_cfm_cb = NULL;
2246 conn->security_cfm_cb = NULL;
2247 conn->disconn_cfm_cb = NULL;
2248
David Herrmann76a68ba2013-04-06 20:28:37 +02002249 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002250
Johan Hedberga664b5b2011-02-19 12:06:02 -03002251 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002252}
2253
2254static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2255{
2256 struct pending_cmd *cmd;
2257
2258 BT_DBG("status %u", status);
2259
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002260 cmd = find_pairing(conn);
2261 if (!cmd)
2262 BT_DBG("Unable to find a pending command");
2263 else
Johan Hedberge2113262012-02-18 15:20:03 +02002264 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002265}
2266
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302267static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2268{
2269 struct pending_cmd *cmd;
2270
2271 BT_DBG("status %u", status);
2272
2273 if (!status)
2274 return;
2275
2276 cmd = find_pairing(conn);
2277 if (!cmd)
2278 BT_DBG("Unable to find a pending command");
2279 else
2280 pairing_complete(cmd, mgmt_status(status));
2281}
2282
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002283static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002284 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002285{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002286 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002287 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002288 struct pending_cmd *cmd;
2289 u8 sec_level, auth_type;
2290 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002291 int err;
2292
2293 BT_DBG("");
2294
Szymon Jancf950a30e2013-01-18 12:48:07 +01002295 memset(&rp, 0, sizeof(rp));
2296 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2297 rp.addr.type = cp->addr.type;
2298
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002299 if (!bdaddr_type_is_valid(cp->addr.type))
2300 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2301 MGMT_STATUS_INVALID_PARAMS,
2302 &rp, sizeof(rp));
2303
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002304 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002306 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002307 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2308 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002309 goto unlock;
2310 }
2311
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002312 sec_level = BT_SECURITY_MEDIUM;
2313 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002314 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002315 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002316 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002317
Andre Guedes591f47f2012-04-24 21:02:49 -03002318 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002319 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2320 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002321 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002322 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2323 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002324
Ville Tervo30e76272011-02-22 16:10:53 -03002325 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002326 int status;
2327
2328 if (PTR_ERR(conn) == -EBUSY)
2329 status = MGMT_STATUS_BUSY;
2330 else
2331 status = MGMT_STATUS_CONNECT_FAILED;
2332
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002333 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002334 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002335 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002336 goto unlock;
2337 }
2338
2339 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002340 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002341 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002342 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002343 goto unlock;
2344 }
2345
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002346 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002347 if (!cmd) {
2348 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002349 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002350 goto unlock;
2351 }
2352
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002353 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002354 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002355 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302356 else
2357 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002358
Johan Hedberge9a416b2011-02-19 12:05:56 -03002359 conn->security_cfm_cb = pairing_complete_cb;
2360 conn->disconn_cfm_cb = pairing_complete_cb;
2361 conn->io_capability = cp->io_cap;
2362 cmd->user_data = conn;
2363
2364 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002365 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002366 pairing_complete(cmd, 0);
2367
2368 err = 0;
2369
2370unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002371 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002372 return err;
2373}
2374
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2376 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002377{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002378 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002379 struct pending_cmd *cmd;
2380 struct hci_conn *conn;
2381 int err;
2382
2383 BT_DBG("");
2384
Johan Hedberg28424702012-02-02 04:02:29 +02002385 hci_dev_lock(hdev);
2386
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002387 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002388 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002389 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002390 goto unlock;
2391 }
2392
Johan Hedberg28424702012-02-02 04:02:29 +02002393 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2394 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002395 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002396 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002397 goto unlock;
2398 }
2399
2400 conn = cmd->user_data;
2401
2402 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002403 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002404 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002405 goto unlock;
2406 }
2407
2408 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002410 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002411 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002412unlock:
2413 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002414 return err;
2415}
2416
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002417static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002418 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002419 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002420{
Johan Hedberga5c29682011-02-19 12:05:57 -03002421 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002422 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002423 int err;
2424
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002425 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002426
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002427 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002428 err = cmd_complete(sk, hdev->id, mgmt_op,
2429 MGMT_STATUS_NOT_POWERED, addr,
2430 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002431 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002432 }
2433
Johan Hedberg1707c602013-03-15 17:07:15 -05002434 if (addr->type == BDADDR_BREDR)
2435 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002436 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002437 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002438
Johan Hedberg272d90d2012-02-09 15:26:12 +02002439 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002440 err = cmd_complete(sk, hdev->id, mgmt_op,
2441 MGMT_STATUS_NOT_CONNECTED, addr,
2442 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002443 goto done;
2444 }
2445
Johan Hedberg1707c602013-03-15 17:07:15 -05002446 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002447 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002448 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002449
Brian Gix5fe57d92011-12-21 16:12:13 -08002450 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002451 err = cmd_complete(sk, hdev->id, mgmt_op,
2452 MGMT_STATUS_SUCCESS, addr,
2453 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002454 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002455 err = cmd_complete(sk, hdev->id, mgmt_op,
2456 MGMT_STATUS_FAILED, addr,
2457 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002458
Brian Gix47c15e22011-11-16 13:53:14 -08002459 goto done;
2460 }
2461
Johan Hedberg1707c602013-03-15 17:07:15 -05002462 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002463 if (!cmd) {
2464 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002465 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002466 }
2467
Brian Gix0df4c182011-11-16 13:53:13 -08002468 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002469 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2470 struct hci_cp_user_passkey_reply cp;
2471
Johan Hedberg1707c602013-03-15 17:07:15 -05002472 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002473 cp.passkey = passkey;
2474 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2475 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002476 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2477 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002478
Johan Hedberga664b5b2011-02-19 12:06:02 -03002479 if (err < 0)
2480 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002481
Brian Gix0df4c182011-11-16 13:53:13 -08002482done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002483 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002484 return err;
2485}
2486
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302487static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2488 void *data, u16 len)
2489{
2490 struct mgmt_cp_pin_code_neg_reply *cp = data;
2491
2492 BT_DBG("");
2493
Johan Hedberg1707c602013-03-15 17:07:15 -05002494 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302495 MGMT_OP_PIN_CODE_NEG_REPLY,
2496 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2497}
2498
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002499static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2500 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002501{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002502 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002503
2504 BT_DBG("");
2505
2506 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002507 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002508 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002509
Johan Hedberg1707c602013-03-15 17:07:15 -05002510 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002511 MGMT_OP_USER_CONFIRM_REPLY,
2512 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002513}
2514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002515static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002516 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002517{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002518 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002519
2520 BT_DBG("");
2521
Johan Hedberg1707c602013-03-15 17:07:15 -05002522 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002523 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2524 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002525}
2526
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002527static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2528 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002529{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002530 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002531
2532 BT_DBG("");
2533
Johan Hedberg1707c602013-03-15 17:07:15 -05002534 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002535 MGMT_OP_USER_PASSKEY_REPLY,
2536 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002537}
2538
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002539static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002540 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002541{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002542 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002543
2544 BT_DBG("");
2545
Johan Hedberg1707c602013-03-15 17:07:15 -05002546 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2548 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002549}
2550
Johan Hedberg13928972013-03-15 17:07:00 -05002551static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002552{
Johan Hedberg13928972013-03-15 17:07:00 -05002553 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002554 struct hci_cp_write_local_name cp;
2555
Johan Hedberg13928972013-03-15 17:07:00 -05002556 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002557
Johan Hedberg890ea892013-03-15 17:06:52 -05002558 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002559}
2560
Johan Hedberg13928972013-03-15 17:07:00 -05002561static void set_name_complete(struct hci_dev *hdev, u8 status)
2562{
2563 struct mgmt_cp_set_local_name *cp;
2564 struct pending_cmd *cmd;
2565
2566 BT_DBG("status 0x%02x", status);
2567
2568 hci_dev_lock(hdev);
2569
2570 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2571 if (!cmd)
2572 goto unlock;
2573
2574 cp = cmd->param;
2575
2576 if (status)
2577 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2578 mgmt_status(status));
2579 else
2580 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2581 cp, sizeof(*cp));
2582
2583 mgmt_pending_remove(cmd);
2584
2585unlock:
2586 hci_dev_unlock(hdev);
2587}
2588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002589static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002591{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002592 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002593 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002594 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002595 int err;
2596
2597 BT_DBG("");
2598
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002599 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002600
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002601 /* If the old values are the same as the new ones just return a
2602 * direct command complete event.
2603 */
2604 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2605 !memcmp(hdev->short_name, cp->short_name,
2606 sizeof(hdev->short_name))) {
2607 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2608 data, len);
2609 goto failed;
2610 }
2611
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002612 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002613
Johan Hedbergb5235a62012-02-21 14:32:24 +02002614 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002615 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002616
2617 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002618 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002619 if (err < 0)
2620 goto failed;
2621
2622 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002623 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002624
Johan Hedbergb5235a62012-02-21 14:32:24 +02002625 goto failed;
2626 }
2627
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002628 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002629 if (!cmd) {
2630 err = -ENOMEM;
2631 goto failed;
2632 }
2633
Johan Hedberg13928972013-03-15 17:07:00 -05002634 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2635
Johan Hedberg890ea892013-03-15 17:06:52 -05002636 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002637
2638 if (lmp_bredr_capable(hdev)) {
2639 update_name(&req);
2640 update_eir(&req);
2641 }
2642
2643 if (lmp_le_capable(hdev))
2644 hci_update_ad(&req);
2645
Johan Hedberg13928972013-03-15 17:07:00 -05002646 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002647 if (err < 0)
2648 mgmt_pending_remove(cmd);
2649
2650failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002651 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002652 return err;
2653}
2654
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002655static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002656 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002657{
Szymon Jancc35938b2011-03-22 13:12:21 +01002658 struct pending_cmd *cmd;
2659 int err;
2660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002661 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002662
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002663 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002664
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002665 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002666 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002667 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002668 goto unlock;
2669 }
2670
Andre Guedes9a1a1992012-07-24 15:03:48 -03002671 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002672 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002673 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002674 goto unlock;
2675 }
2676
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002677 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002678 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002679 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002680 goto unlock;
2681 }
2682
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002683 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002684 if (!cmd) {
2685 err = -ENOMEM;
2686 goto unlock;
2687 }
2688
2689 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2690 if (err < 0)
2691 mgmt_pending_remove(cmd);
2692
2693unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002694 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002695 return err;
2696}
2697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002700{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002701 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002702 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002703 int err;
2704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002705 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002706
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002707 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002708
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002709 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002710 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002711 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002712 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002713 else
Szymon Janca6785be2012-12-13 15:11:21 +01002714 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002715
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002716 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002717 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002718
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002719 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002720 return err;
2721}
2722
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002723static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002724 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002725{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002726 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002727 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002728 int err;
2729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002730 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002732 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002733
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002734 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002735 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002736 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002737 else
Szymon Janca6785be2012-12-13 15:11:21 +01002738 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002739
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002740 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002741 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002742
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002743 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002744 return err;
2745}
2746
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002747static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2748{
2749 struct pending_cmd *cmd;
2750 u8 type;
2751 int err;
2752
2753 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2754
2755 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2756 if (!cmd)
2757 return -ENOENT;
2758
2759 type = hdev->discovery.type;
2760
2761 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2762 &type, sizeof(type));
2763 mgmt_pending_remove(cmd);
2764
2765 return err;
2766}
2767
Andre Guedes7c307722013-04-30 15:29:28 -03002768static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2769{
2770 BT_DBG("status %d", status);
2771
2772 if (status) {
2773 hci_dev_lock(hdev);
2774 mgmt_start_discovery_failed(hdev, status);
2775 hci_dev_unlock(hdev);
2776 return;
2777 }
2778
2779 hci_dev_lock(hdev);
2780 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2781 hci_dev_unlock(hdev);
2782
2783 switch (hdev->discovery.type) {
2784 case DISCOV_TYPE_LE:
2785 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002786 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002787 break;
2788
2789 case DISCOV_TYPE_INTERLEAVED:
2790 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002791 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002792 break;
2793
2794 case DISCOV_TYPE_BREDR:
2795 break;
2796
2797 default:
2798 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2799 }
2800}
2801
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002803 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002804{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002805 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002806 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002807 struct hci_cp_le_set_scan_param param_cp;
2808 struct hci_cp_le_set_scan_enable enable_cp;
2809 struct hci_cp_inquiry inq_cp;
2810 struct hci_request req;
2811 /* General inquiry access code (GIAC) */
2812 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002813 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002814 int err;
2815
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002816 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002818 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002819
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002820 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002821 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002822 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002823 goto failed;
2824 }
2825
Andre Guedes642be6c2012-03-21 00:03:37 -03002826 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2827 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2828 MGMT_STATUS_BUSY);
2829 goto failed;
2830 }
2831
Johan Hedbergff9ef572012-01-04 14:23:45 +02002832 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002833 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002834 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002835 goto failed;
2836 }
2837
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002838 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002839 if (!cmd) {
2840 err = -ENOMEM;
2841 goto failed;
2842 }
2843
Andre Guedes4aab14e2012-02-17 20:39:36 -03002844 hdev->discovery.type = cp->type;
2845
Andre Guedes7c307722013-04-30 15:29:28 -03002846 hci_req_init(&req, hdev);
2847
Andre Guedes4aab14e2012-02-17 20:39:36 -03002848 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002849 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002850 status = mgmt_bredr_support(hdev);
2851 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002852 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002853 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002854 mgmt_pending_remove(cmd);
2855 goto failed;
2856 }
2857
Andre Guedes7c307722013-04-30 15:29:28 -03002858 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2859 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2860 MGMT_STATUS_BUSY);
2861 mgmt_pending_remove(cmd);
2862 goto failed;
2863 }
2864
2865 hci_inquiry_cache_flush(hdev);
2866
2867 memset(&inq_cp, 0, sizeof(inq_cp));
2868 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002869 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002870 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002871 break;
2872
2873 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002874 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002875 status = mgmt_le_support(hdev);
2876 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002877 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002878 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002879 mgmt_pending_remove(cmd);
2880 goto failed;
2881 }
2882
Andre Guedes7c307722013-04-30 15:29:28 -03002883 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002884 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002885 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2886 MGMT_STATUS_NOT_SUPPORTED);
2887 mgmt_pending_remove(cmd);
2888 goto failed;
2889 }
2890
Andre Guedes7c307722013-04-30 15:29:28 -03002891 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2892 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2893 MGMT_STATUS_REJECTED);
2894 mgmt_pending_remove(cmd);
2895 goto failed;
2896 }
2897
2898 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2899 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2900 MGMT_STATUS_BUSY);
2901 mgmt_pending_remove(cmd);
2902 goto failed;
2903 }
2904
2905 memset(&param_cp, 0, sizeof(param_cp));
2906 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002907 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2908 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002909 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2910 &param_cp);
2911
2912 memset(&enable_cp, 0, sizeof(enable_cp));
2913 enable_cp.enable = LE_SCAN_ENABLE;
2914 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2915 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2916 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002917 break;
2918
Andre Guedesf39799f2012-02-17 20:39:35 -03002919 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002920 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2921 MGMT_STATUS_INVALID_PARAMS);
2922 mgmt_pending_remove(cmd);
2923 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002924 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002925
Andre Guedes7c307722013-04-30 15:29:28 -03002926 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002927 if (err < 0)
2928 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002929 else
2930 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002931
2932failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002933 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002934 return err;
2935}
2936
Andre Guedes1183fdc2013-04-30 15:29:35 -03002937static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2938{
2939 struct pending_cmd *cmd;
2940 int err;
2941
2942 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2943 if (!cmd)
2944 return -ENOENT;
2945
2946 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2947 &hdev->discovery.type, sizeof(hdev->discovery.type));
2948 mgmt_pending_remove(cmd);
2949
2950 return err;
2951}
2952
Andre Guedes0e05bba2013-04-30 15:29:33 -03002953static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2954{
2955 BT_DBG("status %d", status);
2956
2957 hci_dev_lock(hdev);
2958
2959 if (status) {
2960 mgmt_stop_discovery_failed(hdev, status);
2961 goto unlock;
2962 }
2963
2964 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2965
2966unlock:
2967 hci_dev_unlock(hdev);
2968}
2969
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002970static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002971 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002972{
Johan Hedbergd9306502012-02-20 23:25:18 +02002973 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002974 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002975 struct hci_cp_remote_name_req_cancel cp;
2976 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002977 struct hci_request req;
2978 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002979 int err;
2980
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002981 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002982
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002983 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002984
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002985 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002986 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002987 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2988 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002989 goto unlock;
2990 }
2991
2992 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002993 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002994 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2995 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002996 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002997 }
2998
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002999 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003000 if (!cmd) {
3001 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003002 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003003 }
3004
Andre Guedes0e05bba2013-04-30 15:29:33 -03003005 hci_req_init(&req, hdev);
3006
Andre Guedese0d9727e2012-03-20 15:15:36 -03003007 switch (hdev->discovery.state) {
3008 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003009 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3010 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3011 } else {
3012 cancel_delayed_work(&hdev->le_scan_disable);
3013
3014 memset(&enable_cp, 0, sizeof(enable_cp));
3015 enable_cp.enable = LE_SCAN_DISABLE;
3016 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3017 sizeof(enable_cp), &enable_cp);
3018 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003019
Andre Guedese0d9727e2012-03-20 15:15:36 -03003020 break;
3021
3022 case DISCOVERY_RESOLVING:
3023 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003024 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003025 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003026 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003027 err = cmd_complete(sk, hdev->id,
3028 MGMT_OP_STOP_DISCOVERY, 0,
3029 &mgmt_cp->type,
3030 sizeof(mgmt_cp->type));
3031 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3032 goto unlock;
3033 }
3034
3035 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003036 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3037 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003038
3039 break;
3040
3041 default:
3042 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003043
3044 mgmt_pending_remove(cmd);
3045 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3046 MGMT_STATUS_FAILED, &mgmt_cp->type,
3047 sizeof(mgmt_cp->type));
3048 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003049 }
3050
Andre Guedes0e05bba2013-04-30 15:29:33 -03003051 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003052 if (err < 0)
3053 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003054 else
3055 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003056
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003057unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003058 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003059 return err;
3060}
3061
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003062static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003063 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003064{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003065 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003066 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003067 int err;
3068
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003069 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003070
Johan Hedberg561aafb2012-01-04 13:31:59 +02003071 hci_dev_lock(hdev);
3072
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003073 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003074 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003075 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003076 goto failed;
3077 }
3078
Johan Hedberga198e7b2012-02-17 14:27:06 +02003079 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003080 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003081 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003082 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003083 goto failed;
3084 }
3085
3086 if (cp->name_known) {
3087 e->name_state = NAME_KNOWN;
3088 list_del(&e->list);
3089 } else {
3090 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003091 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003092 }
3093
Johan Hedberge3846622013-01-09 15:29:33 +02003094 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3095 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003096
3097failed:
3098 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003099 return err;
3100}
3101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003102static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003103 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003104{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003105 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003106 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003107 int err;
3108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003109 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003110
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003111 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003112 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3113 MGMT_STATUS_INVALID_PARAMS,
3114 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003115
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003116 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003117
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003118 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003119 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003120 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003121 else
Szymon Janca6785be2012-12-13 15:11:21 +01003122 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003123
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003124 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003125 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003126
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003127 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003128
3129 return err;
3130}
3131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003132static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003133 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003134{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003135 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003136 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003137 int err;
3138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003139 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003140
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003141 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003142 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3143 MGMT_STATUS_INVALID_PARAMS,
3144 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003146 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003147
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003148 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003149 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003150 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003151 else
Szymon Janca6785be2012-12-13 15:11:21 +01003152 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003153
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003154 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003155 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003156
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003157 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003158
3159 return err;
3160}
3161
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003162static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3163 u16 len)
3164{
3165 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003166 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003167 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003168 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003169
3170 BT_DBG("%s", hdev->name);
3171
Szymon Jancc72d4b82012-03-16 16:02:57 +01003172 source = __le16_to_cpu(cp->source);
3173
3174 if (source > 0x0002)
3175 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3176 MGMT_STATUS_INVALID_PARAMS);
3177
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003178 hci_dev_lock(hdev);
3179
Szymon Jancc72d4b82012-03-16 16:02:57 +01003180 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003181 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3182 hdev->devid_product = __le16_to_cpu(cp->product);
3183 hdev->devid_version = __le16_to_cpu(cp->version);
3184
3185 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3186
Johan Hedberg890ea892013-03-15 17:06:52 -05003187 hci_req_init(&req, hdev);
3188 update_eir(&req);
3189 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003190
3191 hci_dev_unlock(hdev);
3192
3193 return err;
3194}
3195
Johan Hedberg4375f102013-09-25 13:26:10 +03003196static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3197{
3198 struct cmd_lookup match = { NULL, hdev };
3199
3200 if (status) {
3201 u8 mgmt_err = mgmt_status(status);
3202
3203 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3204 cmd_status_rsp, &mgmt_err);
3205 return;
3206 }
3207
3208 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3209 &match);
3210
3211 new_settings(hdev, match.sk);
3212
3213 if (match.sk)
3214 sock_put(match.sk);
3215}
3216
3217static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3218{
3219 struct mgmt_mode *cp = data;
3220 struct pending_cmd *cmd;
3221 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003222 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003223 int err;
3224
3225 BT_DBG("request for %s", hdev->name);
3226
Johan Hedberge6fe7982013-10-02 15:45:22 +03003227 status = mgmt_le_support(hdev);
3228 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003229 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003230 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003231
3232 if (cp->val != 0x00 && cp->val != 0x01)
3233 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3234 MGMT_STATUS_INVALID_PARAMS);
3235
3236 hci_dev_lock(hdev);
3237
3238 val = !!cp->val;
3239 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3240
3241 if (!hdev_is_powered(hdev) || val == enabled) {
3242 bool changed = false;
3243
3244 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3245 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3246 changed = true;
3247 }
3248
3249 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3250 if (err < 0)
3251 goto unlock;
3252
3253 if (changed)
3254 err = new_settings(hdev, sk);
3255
3256 goto unlock;
3257 }
3258
3259 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3260 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3261 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3262 MGMT_STATUS_BUSY);
3263 goto unlock;
3264 }
3265
3266 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3267 if (!cmd) {
3268 err = -ENOMEM;
3269 goto unlock;
3270 }
3271
3272 hci_req_init(&req, hdev);
3273
3274 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3275
3276 err = hci_req_run(&req, set_advertising_complete);
3277 if (err < 0)
3278 mgmt_pending_remove(cmd);
3279
3280unlock:
3281 hci_dev_unlock(hdev);
3282 return err;
3283}
3284
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003285static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3286 void *data, u16 len)
3287{
3288 struct mgmt_cp_set_static_address *cp = data;
3289 int err;
3290
3291 BT_DBG("%s", hdev->name);
3292
Marcel Holtmann62af4442013-10-02 22:10:32 -07003293 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003294 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003295 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003296
3297 if (hdev_is_powered(hdev))
3298 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3299 MGMT_STATUS_REJECTED);
3300
3301 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3302 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3303 return cmd_status(sk, hdev->id,
3304 MGMT_OP_SET_STATIC_ADDRESS,
3305 MGMT_STATUS_INVALID_PARAMS);
3306
3307 /* Two most significant bits shall be set */
3308 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3309 return cmd_status(sk, hdev->id,
3310 MGMT_OP_SET_STATIC_ADDRESS,
3311 MGMT_STATUS_INVALID_PARAMS);
3312 }
3313
3314 hci_dev_lock(hdev);
3315
3316 bacpy(&hdev->static_addr, &cp->bdaddr);
3317
3318 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3319
3320 hci_dev_unlock(hdev);
3321
3322 return err;
3323}
3324
Johan Hedberg33e38b32013-03-15 17:07:05 -05003325static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3326{
3327 struct pending_cmd *cmd;
3328
3329 BT_DBG("status 0x%02x", status);
3330
3331 hci_dev_lock(hdev);
3332
3333 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3334 if (!cmd)
3335 goto unlock;
3336
3337 if (status) {
3338 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3339 mgmt_status(status));
3340 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003341 struct mgmt_mode *cp = cmd->param;
3342
3343 if (cp->val)
3344 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3345 else
3346 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3347
Johan Hedberg33e38b32013-03-15 17:07:05 -05003348 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3349 new_settings(hdev, cmd->sk);
3350 }
3351
3352 mgmt_pending_remove(cmd);
3353
3354unlock:
3355 hci_dev_unlock(hdev);
3356}
3357
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003358static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003359 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003360{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003361 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003362 struct pending_cmd *cmd;
3363 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003364 int err;
3365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003366 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003367
Johan Hedberg56f87902013-10-02 13:43:13 +03003368 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3369 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003370 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3371 MGMT_STATUS_NOT_SUPPORTED);
3372
Johan Hedberga7e80f22013-01-09 16:05:19 +02003373 if (cp->val != 0x00 && cp->val != 0x01)
3374 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3375 MGMT_STATUS_INVALID_PARAMS);
3376
Johan Hedberg5400c042012-02-21 16:40:33 +02003377 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003378 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003379 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003380
3381 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003382 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003383 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003384
3385 hci_dev_lock(hdev);
3386
Johan Hedberg05cbf292013-03-15 17:07:07 -05003387 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3388 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3389 MGMT_STATUS_BUSY);
3390 goto unlock;
3391 }
3392
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003393 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3394 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3395 hdev);
3396 goto unlock;
3397 }
3398
Johan Hedberg33e38b32013-03-15 17:07:05 -05003399 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3400 data, len);
3401 if (!cmd) {
3402 err = -ENOMEM;
3403 goto unlock;
3404 }
3405
3406 hci_req_init(&req, hdev);
3407
Johan Hedberg406d7802013-03-15 17:07:09 -05003408 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003409
3410 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003411 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003412 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003413 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003414 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003415 }
3416
Johan Hedberg33e38b32013-03-15 17:07:05 -05003417unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003418 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003419
Antti Julkuf6422ec2011-06-22 13:11:56 +03003420 return err;
3421}
3422
Johan Hedberg0663ca22013-10-02 13:43:14 +03003423static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3424{
3425 struct pending_cmd *cmd;
3426
3427 BT_DBG("status 0x%02x", status);
3428
3429 hci_dev_lock(hdev);
3430
3431 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3432 if (!cmd)
3433 goto unlock;
3434
3435 if (status) {
3436 u8 mgmt_err = mgmt_status(status);
3437
3438 /* We need to restore the flag if related HCI commands
3439 * failed.
3440 */
3441 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3442
3443 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3444 } else {
3445 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3446 new_settings(hdev, cmd->sk);
3447 }
3448
3449 mgmt_pending_remove(cmd);
3450
3451unlock:
3452 hci_dev_unlock(hdev);
3453}
3454
3455static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3456{
3457 struct mgmt_mode *cp = data;
3458 struct pending_cmd *cmd;
3459 struct hci_request req;
3460 int err;
3461
3462 BT_DBG("request for %s", hdev->name);
3463
3464 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3465 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3466 MGMT_STATUS_NOT_SUPPORTED);
3467
3468 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3469 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3470 MGMT_STATUS_REJECTED);
3471
3472 if (cp->val != 0x00 && cp->val != 0x01)
3473 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3474 MGMT_STATUS_INVALID_PARAMS);
3475
3476 hci_dev_lock(hdev);
3477
3478 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3479 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3480 goto unlock;
3481 }
3482
3483 if (!hdev_is_powered(hdev)) {
3484 if (!cp->val) {
3485 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3486 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3487 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3488 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3489 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3490 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3491 }
3492
3493 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3494
3495 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3496 if (err < 0)
3497 goto unlock;
3498
3499 err = new_settings(hdev, sk);
3500 goto unlock;
3501 }
3502
3503 /* Reject disabling when powered on */
3504 if (!cp->val) {
3505 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3506 MGMT_STATUS_REJECTED);
3507 goto unlock;
3508 }
3509
3510 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3511 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3512 MGMT_STATUS_BUSY);
3513 goto unlock;
3514 }
3515
3516 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3517 if (!cmd) {
3518 err = -ENOMEM;
3519 goto unlock;
3520 }
3521
3522 /* We need to flip the bit already here so that hci_update_ad
3523 * generates the correct flags.
3524 */
3525 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3526
3527 hci_req_init(&req, hdev);
3528 hci_update_ad(&req);
3529 err = hci_req_run(&req, set_bredr_complete);
3530 if (err < 0)
3531 mgmt_pending_remove(cmd);
3532
3533unlock:
3534 hci_dev_unlock(hdev);
3535 return err;
3536}
3537
Johan Hedberg3f706b72013-01-20 14:27:16 +02003538static bool ltk_is_valid(struct mgmt_ltk_info *key)
3539{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003540 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3541 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003542 if (key->master != 0x00 && key->master != 0x01)
3543 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003544 if (!bdaddr_type_is_le(key->addr.type))
3545 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003546 return true;
3547}
3548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003549static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003550 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003551{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003552 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3553 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003554 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003555
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003556 BT_DBG("request for %s", hdev->name);
3557
3558 if (!lmp_le_capable(hdev))
3559 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3560 MGMT_STATUS_NOT_SUPPORTED);
3561
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003562 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003563
3564 expected_len = sizeof(*cp) + key_count *
3565 sizeof(struct mgmt_ltk_info);
3566 if (expected_len != len) {
3567 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003568 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003569 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003570 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003571 }
3572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003573 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003574
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003575 for (i = 0; i < key_count; i++) {
3576 struct mgmt_ltk_info *key = &cp->keys[i];
3577
Johan Hedberg3f706b72013-01-20 14:27:16 +02003578 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003579 return cmd_status(sk, hdev->id,
3580 MGMT_OP_LOAD_LONG_TERM_KEYS,
3581 MGMT_STATUS_INVALID_PARAMS);
3582 }
3583
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003584 hci_dev_lock(hdev);
3585
3586 hci_smp_ltks_clear(hdev);
3587
3588 for (i = 0; i < key_count; i++) {
3589 struct mgmt_ltk_info *key = &cp->keys[i];
3590 u8 type;
3591
3592 if (key->master)
3593 type = HCI_SMP_LTK;
3594 else
3595 type = HCI_SMP_LTK_SLAVE;
3596
Hemant Gupta4596fde2012-04-16 14:57:40 +05303597 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003598 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003599 type, 0, key->authenticated, key->val,
3600 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003601 }
3602
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003603 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3604 NULL, 0);
3605
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003606 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003607
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003608 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003609}
3610
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003611static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003612 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3613 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003614 bool var_len;
3615 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003616} mgmt_handlers[] = {
3617 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003618 { read_version, false, MGMT_READ_VERSION_SIZE },
3619 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3620 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3621 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3622 { set_powered, false, MGMT_SETTING_SIZE },
3623 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3624 { set_connectable, false, MGMT_SETTING_SIZE },
3625 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3626 { set_pairable, false, MGMT_SETTING_SIZE },
3627 { set_link_security, false, MGMT_SETTING_SIZE },
3628 { set_ssp, false, MGMT_SETTING_SIZE },
3629 { set_hs, false, MGMT_SETTING_SIZE },
3630 { set_le, false, MGMT_SETTING_SIZE },
3631 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3632 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3633 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3634 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3635 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3636 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3637 { disconnect, false, MGMT_DISCONNECT_SIZE },
3638 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3639 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3640 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3641 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3642 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3643 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3644 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3645 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3646 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3647 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3648 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3649 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3650 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3651 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3652 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3653 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3654 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3655 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3656 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003657 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003658 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003659 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003660 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003661};
3662
3663
Johan Hedberg03811012010-12-08 00:21:06 +02003664int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3665{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003666 void *buf;
3667 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003668 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003669 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003670 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003671 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003672 int err;
3673
3674 BT_DBG("got %zu bytes", msglen);
3675
3676 if (msglen < sizeof(*hdr))
3677 return -EINVAL;
3678
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003679 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003680 if (!buf)
3681 return -ENOMEM;
3682
3683 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3684 err = -EFAULT;
3685 goto done;
3686 }
3687
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003688 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003689 opcode = __le16_to_cpu(hdr->opcode);
3690 index = __le16_to_cpu(hdr->index);
3691 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003692
3693 if (len != msglen - sizeof(*hdr)) {
3694 err = -EINVAL;
3695 goto done;
3696 }
3697
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003698 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003699 hdev = hci_dev_get(index);
3700 if (!hdev) {
3701 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003702 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003703 goto done;
3704 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003705
3706 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3707 err = cmd_status(sk, index, opcode,
3708 MGMT_STATUS_INVALID_INDEX);
3709 goto done;
3710 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003711 }
3712
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003713 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003714 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003715 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003716 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003717 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003718 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003719 }
3720
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003721 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003722 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003723 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003724 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003725 goto done;
3726 }
3727
Johan Hedbergbe22b542012-03-01 22:24:41 +02003728 handler = &mgmt_handlers[opcode];
3729
3730 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003731 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003732 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003733 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003734 goto done;
3735 }
3736
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003737 if (hdev)
3738 mgmt_init_hdev(sk, hdev);
3739
3740 cp = buf + sizeof(*hdr);
3741
Johan Hedbergbe22b542012-03-01 22:24:41 +02003742 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003743 if (err < 0)
3744 goto done;
3745
Johan Hedberg03811012010-12-08 00:21:06 +02003746 err = msglen;
3747
3748done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003749 if (hdev)
3750 hci_dev_put(hdev);
3751
Johan Hedberg03811012010-12-08 00:21:06 +02003752 kfree(buf);
3753 return err;
3754}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003755
Johan Hedberg744cf192011-11-08 20:40:14 +02003756int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003757{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003758 if (!mgmt_valid_hdev(hdev))
3759 return -ENOTSUPP;
3760
Johan Hedberg744cf192011-11-08 20:40:14 +02003761 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003762}
3763
Johan Hedberg744cf192011-11-08 20:40:14 +02003764int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003765{
Johan Hedberg5f159032012-03-02 03:13:19 +02003766 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003767
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003768 if (!mgmt_valid_hdev(hdev))
3769 return -ENOTSUPP;
3770
Johan Hedberg744cf192011-11-08 20:40:14 +02003771 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003772
Johan Hedberg744cf192011-11-08 20:40:14 +02003773 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003774}
3775
Johan Hedberg890ea892013-03-15 17:06:52 -05003776static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003777{
Johan Hedberg890ea892013-03-15 17:06:52 -05003778 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003779 u8 scan = 0;
3780
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003781 /* Ensure that fast connectable is disabled. This function will
3782 * not do anything if the page scan parameters are already what
3783 * they should be.
3784 */
3785 write_fast_connectable(req, false);
3786
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003787 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3788 scan |= SCAN_PAGE;
3789 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3790 scan |= SCAN_INQUIRY;
3791
Johan Hedberg890ea892013-03-15 17:06:52 -05003792 if (scan)
3793 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003794}
3795
Johan Hedberg229ab392013-03-15 17:06:53 -05003796static void powered_complete(struct hci_dev *hdev, u8 status)
3797{
3798 struct cmd_lookup match = { NULL, hdev };
3799
3800 BT_DBG("status 0x%02x", status);
3801
3802 hci_dev_lock(hdev);
3803
3804 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3805
3806 new_settings(hdev, match.sk);
3807
3808 hci_dev_unlock(hdev);
3809
3810 if (match.sk)
3811 sock_put(match.sk);
3812}
3813
Johan Hedberg70da6242013-03-15 17:06:51 -05003814static int powered_update_hci(struct hci_dev *hdev)
3815{
Johan Hedberg890ea892013-03-15 17:06:52 -05003816 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003817 u8 link_sec;
3818
Johan Hedberg890ea892013-03-15 17:06:52 -05003819 hci_req_init(&req, hdev);
3820
Johan Hedberg70da6242013-03-15 17:06:51 -05003821 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3822 !lmp_host_ssp_capable(hdev)) {
3823 u8 ssp = 1;
3824
Johan Hedberg890ea892013-03-15 17:06:52 -05003825 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003826 }
3827
Johan Hedbergc73eee92013-04-19 18:35:21 +03003828 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3829 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003830 struct hci_cp_write_le_host_supported cp;
3831
3832 cp.le = 1;
3833 cp.simul = lmp_le_br_capable(hdev);
3834
3835 /* Check first if we already have the right
3836 * host state (host features set)
3837 */
3838 if (cp.le != lmp_host_le_capable(hdev) ||
3839 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003840 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3841 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003842
3843 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3844 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003845 }
3846
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003847 if (lmp_le_capable(hdev)) {
3848 /* Set random address to static address if configured */
3849 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3850 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3851 &hdev->static_addr);
3852 }
3853
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003854 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3855 u8 adv = 0x01;
3856
3857 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3858 }
3859
Johan Hedberg70da6242013-03-15 17:06:51 -05003860 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3861 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003862 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3863 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003864
3865 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003866 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3867 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003868 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003869 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003870 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003871 }
3872
Johan Hedberg229ab392013-03-15 17:06:53 -05003873 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003874}
3875
Johan Hedberg744cf192011-11-08 20:40:14 +02003876int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003877{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003878 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003879 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3880 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003881 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003882
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003883 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3884 return 0;
3885
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003886 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003887 if (powered_update_hci(hdev) == 0)
3888 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003889
Johan Hedberg229ab392013-03-15 17:06:53 -05003890 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3891 &match);
3892 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003893 }
3894
Johan Hedberg229ab392013-03-15 17:06:53 -05003895 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3896 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3897
3898 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3899 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3900 zero_cod, sizeof(zero_cod), NULL);
3901
3902new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003903 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003904
3905 if (match.sk)
3906 sock_put(match.sk);
3907
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003908 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003909}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003910
Johan Hedberg96570ff2013-05-29 09:51:29 +03003911int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3912{
3913 struct pending_cmd *cmd;
3914 u8 status;
3915
3916 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3917 if (!cmd)
3918 return -ENOENT;
3919
3920 if (err == -ERFKILL)
3921 status = MGMT_STATUS_RFKILLED;
3922 else
3923 status = MGMT_STATUS_FAILED;
3924
3925 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3926
3927 mgmt_pending_remove(cmd);
3928
3929 return err;
3930}
3931
Johan Hedberg744cf192011-11-08 20:40:14 +02003932int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003933{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003934 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003935 bool changed = false;
3936 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003937
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003938 if (discoverable) {
3939 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3940 changed = true;
3941 } else {
3942 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3943 changed = true;
3944 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003945
Johan Hedberged9b5f22012-02-21 20:47:06 +02003946 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003947 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003948
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003949 if (changed)
3950 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003951
Johan Hedberg73f22f62010-12-29 16:00:25 +02003952 if (match.sk)
3953 sock_put(match.sk);
3954
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003955 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003956}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003957
Johan Hedberg744cf192011-11-08 20:40:14 +02003958int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003959{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003960 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003961 bool changed = false;
3962 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003963
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003964 if (connectable) {
3965 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3966 changed = true;
3967 } else {
3968 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3969 changed = true;
3970 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003971
Johan Hedberg2b76f452013-03-15 17:07:04 -05003972 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003973
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003974 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003975 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003976
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003977 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003978}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003979
Johan Hedberg744cf192011-11-08 20:40:14 +02003980int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003981{
Johan Hedbergca69b792011-11-11 18:10:00 +02003982 u8 mgmt_err = mgmt_status(status);
3983
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003984 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003985 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003986 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003987
3988 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003989 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003990 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003991
3992 return 0;
3993}
3994
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003995int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3996 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003997{
Johan Hedberg86742e12011-11-07 23:13:38 +02003998 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003999
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004000 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004001
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004002 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004003 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004004 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004005 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004006 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004007 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004008
Johan Hedberg744cf192011-11-08 20:40:14 +02004009 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004010}
Johan Hedbergf7520542011-01-20 12:34:39 +02004011
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004012int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4013{
4014 struct mgmt_ev_new_long_term_key ev;
4015
4016 memset(&ev, 0, sizeof(ev));
4017
4018 ev.store_hint = persistent;
4019 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004020 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004021 ev.key.authenticated = key->authenticated;
4022 ev.key.enc_size = key->enc_size;
4023 ev.key.ediv = key->ediv;
4024
4025 if (key->type == HCI_SMP_LTK)
4026 ev.key.master = 1;
4027
4028 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4029 memcpy(ev.key.val, key->val, sizeof(key->val));
4030
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004031 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4032 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004033}
4034
Johan Hedbergafc747a2012-01-15 18:11:07 +02004035int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004036 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4037 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004038{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004039 char buf[512];
4040 struct mgmt_ev_device_connected *ev = (void *) buf;
4041 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004042
Johan Hedbergb644ba32012-01-17 21:48:47 +02004043 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004044 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004045
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004046 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004047
Johan Hedbergb644ba32012-01-17 21:48:47 +02004048 if (name_len > 0)
4049 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004050 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004051
4052 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004053 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004054 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004055
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004056 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004057
4058 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004059 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004060}
4061
Johan Hedberg8962ee72011-01-20 12:40:27 +02004062static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4063{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004064 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004065 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004066 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004067
Johan Hedberg88c3df12012-02-09 14:27:38 +02004068 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4069 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004070
Johan Hedbergaee9b212012-02-18 15:07:59 +02004071 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004072 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004073
4074 *sk = cmd->sk;
4075 sock_hold(*sk);
4076
Johan Hedberga664b5b2011-02-19 12:06:02 -03004077 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004078}
4079
Johan Hedberg124f6e32012-02-09 13:50:12 +02004080static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004081{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004082 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004083 struct mgmt_cp_unpair_device *cp = cmd->param;
4084 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004085
4086 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004087 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4088 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004089
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004090 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4091
Johan Hedbergaee9b212012-02-18 15:07:59 +02004092 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004093
4094 mgmt_pending_remove(cmd);
4095}
4096
Johan Hedbergafc747a2012-01-15 18:11:07 +02004097int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004098 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004099{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004100 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004101 struct sock *sk = NULL;
4102 int err;
4103
Johan Hedberg744cf192011-11-08 20:40:14 +02004104 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004105
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004106 bacpy(&ev.addr.bdaddr, bdaddr);
4107 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4108 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004109
Johan Hedbergafc747a2012-01-15 18:11:07 +02004110 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004111 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004112
4113 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004114 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004115
Johan Hedberg124f6e32012-02-09 13:50:12 +02004116 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004117 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004118
Johan Hedberg8962ee72011-01-20 12:40:27 +02004119 return err;
4120}
4121
Johan Hedberg88c3df12012-02-09 14:27:38 +02004122int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004123 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004124{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004125 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004126 struct pending_cmd *cmd;
4127 int err;
4128
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004129 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4130 hdev);
4131
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004132 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004133 if (!cmd)
4134 return -ENOENT;
4135
Johan Hedberg88c3df12012-02-09 14:27:38 +02004136 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004137 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004138
Johan Hedberg88c3df12012-02-09 14:27:38 +02004139 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004140 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004141
Johan Hedberga664b5b2011-02-19 12:06:02 -03004142 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004143
4144 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004145}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004146
Johan Hedberg48264f02011-11-09 13:58:58 +02004147int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004148 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004149{
4150 struct mgmt_ev_connect_failed ev;
4151
Johan Hedberg4c659c32011-11-07 23:13:39 +02004152 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004153 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004154 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004155
Johan Hedberg744cf192011-11-08 20:40:14 +02004156 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004157}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004158
Johan Hedberg744cf192011-11-08 20:40:14 +02004159int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004160{
4161 struct mgmt_ev_pin_code_request ev;
4162
Johan Hedbergd8457692012-02-17 14:24:57 +02004163 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004164 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004165 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004166
Johan Hedberg744cf192011-11-08 20:40:14 +02004167 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004168 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004169}
4170
Johan Hedberg744cf192011-11-08 20:40:14 +02004171int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004172 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004173{
4174 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004175 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004176 int err;
4177
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004178 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004179 if (!cmd)
4180 return -ENOENT;
4181
Johan Hedbergd8457692012-02-17 14:24:57 +02004182 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004183 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004184
Johan Hedbergaee9b212012-02-18 15:07:59 +02004185 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004186 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004187
Johan Hedberga664b5b2011-02-19 12:06:02 -03004188 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004189
4190 return err;
4191}
4192
Johan Hedberg744cf192011-11-08 20:40:14 +02004193int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004194 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004195{
4196 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004197 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004198 int err;
4199
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004200 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004201 if (!cmd)
4202 return -ENOENT;
4203
Johan Hedbergd8457692012-02-17 14:24:57 +02004204 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004205 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004206
Johan Hedbergaee9b212012-02-18 15:07:59 +02004207 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004208 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004209
Johan Hedberga664b5b2011-02-19 12:06:02 -03004210 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004211
4212 return err;
4213}
Johan Hedberga5c29682011-02-19 12:05:57 -03004214
Johan Hedberg744cf192011-11-08 20:40:14 +02004215int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004216 u8 link_type, u8 addr_type, __le32 value,
4217 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004218{
4219 struct mgmt_ev_user_confirm_request ev;
4220
Johan Hedberg744cf192011-11-08 20:40:14 +02004221 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004222
Johan Hedberg272d90d2012-02-09 15:26:12 +02004223 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004224 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004225 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004226 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004227
Johan Hedberg744cf192011-11-08 20:40:14 +02004228 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004229 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004230}
4231
Johan Hedberg272d90d2012-02-09 15:26:12 +02004232int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004233 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004234{
4235 struct mgmt_ev_user_passkey_request ev;
4236
4237 BT_DBG("%s", hdev->name);
4238
Johan Hedberg272d90d2012-02-09 15:26:12 +02004239 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004240 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004241
4242 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004243 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004244}
4245
Brian Gix0df4c182011-11-16 13:53:13 -08004246static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004247 u8 link_type, u8 addr_type, u8 status,
4248 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004249{
4250 struct pending_cmd *cmd;
4251 struct mgmt_rp_user_confirm_reply rp;
4252 int err;
4253
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004254 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004255 if (!cmd)
4256 return -ENOENT;
4257
Johan Hedberg272d90d2012-02-09 15:26:12 +02004258 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004259 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004260 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004261 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004262
Johan Hedberga664b5b2011-02-19 12:06:02 -03004263 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004264
4265 return err;
4266}
4267
Johan Hedberg744cf192011-11-08 20:40:14 +02004268int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004269 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004270{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004271 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004272 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004273}
4274
Johan Hedberg272d90d2012-02-09 15:26:12 +02004275int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004276 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004277{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004278 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004279 status,
4280 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004281}
Johan Hedberg2a611692011-02-19 12:06:00 -03004282
Brian Gix604086b2011-11-23 08:28:33 -08004283int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004284 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004285{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004286 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004287 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004288}
4289
Johan Hedberg272d90d2012-02-09 15:26:12 +02004290int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004291 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004292{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004293 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004294 status,
4295 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004296}
4297
Johan Hedberg92a25252012-09-06 18:39:26 +03004298int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4299 u8 link_type, u8 addr_type, u32 passkey,
4300 u8 entered)
4301{
4302 struct mgmt_ev_passkey_notify ev;
4303
4304 BT_DBG("%s", hdev->name);
4305
4306 bacpy(&ev.addr.bdaddr, bdaddr);
4307 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4308 ev.passkey = __cpu_to_le32(passkey);
4309 ev.entered = entered;
4310
4311 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4312}
4313
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004314int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004315 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004316{
4317 struct mgmt_ev_auth_failed ev;
4318
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004319 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004320 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004321 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004322
Johan Hedberg744cf192011-11-08 20:40:14 +02004323 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004324}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004325
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004326int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4327{
4328 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004329 bool changed = false;
4330 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004331
4332 if (status) {
4333 u8 mgmt_err = mgmt_status(status);
4334 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004335 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004336 return 0;
4337 }
4338
Johan Hedberg47990ea2012-02-22 11:58:37 +02004339 if (test_bit(HCI_AUTH, &hdev->flags)) {
4340 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4341 changed = true;
4342 } else {
4343 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4344 changed = true;
4345 }
4346
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004347 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004348 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004349
Johan Hedberg47990ea2012-02-22 11:58:37 +02004350 if (changed)
4351 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004352
4353 if (match.sk)
4354 sock_put(match.sk);
4355
4356 return err;
4357}
4358
Johan Hedberg890ea892013-03-15 17:06:52 -05004359static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004360{
Johan Hedberg890ea892013-03-15 17:06:52 -05004361 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004362 struct hci_cp_write_eir cp;
4363
Johan Hedberg976eb202012-10-24 21:12:01 +03004364 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004365 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004366
Johan Hedbergc80da272012-02-22 15:38:48 +02004367 memset(hdev->eir, 0, sizeof(hdev->eir));
4368
Johan Hedbergcacaf522012-02-21 00:52:42 +02004369 memset(&cp, 0, sizeof(cp));
4370
Johan Hedberg890ea892013-03-15 17:06:52 -05004371 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004372}
4373
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004374int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004375{
4376 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004377 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004378 bool changed = false;
4379 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004380
4381 if (status) {
4382 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004383
4384 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004385 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004386 err = new_settings(hdev, NULL);
4387
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004388 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4389 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004390
4391 return err;
4392 }
4393
4394 if (enable) {
4395 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4396 changed = true;
4397 } else {
4398 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4399 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004400 }
4401
4402 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4403
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004404 if (changed)
4405 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004406
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004407 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004408 sock_put(match.sk);
4409
Johan Hedberg890ea892013-03-15 17:06:52 -05004410 hci_req_init(&req, hdev);
4411
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004412 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004413 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004414 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004415 clear_eir(&req);
4416
4417 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004418
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004419 return err;
4420}
4421
Johan Hedberg92da6092013-03-15 17:06:55 -05004422static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004423{
4424 struct cmd_lookup *match = data;
4425
Johan Hedberg90e70452012-02-23 23:09:40 +02004426 if (match->sk == NULL) {
4427 match->sk = cmd->sk;
4428 sock_hold(match->sk);
4429 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004430}
4431
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004432int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004433 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004434{
Johan Hedberg90e70452012-02-23 23:09:40 +02004435 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4436 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004437
Johan Hedberg92da6092013-03-15 17:06:55 -05004438 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4439 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4440 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004441
4442 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004443 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4444 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004445
4446 if (match.sk)
4447 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004448
4449 return err;
4450}
4451
Johan Hedberg744cf192011-11-08 20:40:14 +02004452int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004453{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004454 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004455 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004456
Johan Hedberg13928972013-03-15 17:07:00 -05004457 if (status)
4458 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004459
4460 memset(&ev, 0, sizeof(ev));
4461 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004462 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004463
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004464 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004465 if (!cmd) {
4466 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004467
Johan Hedberg13928972013-03-15 17:07:00 -05004468 /* If this is a HCI command related to powering on the
4469 * HCI dev don't send any mgmt signals.
4470 */
4471 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4472 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004473 }
4474
Johan Hedberg13928972013-03-15 17:07:00 -05004475 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4476 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004477}
Szymon Jancc35938b2011-03-22 13:12:21 +01004478
Johan Hedberg744cf192011-11-08 20:40:14 +02004479int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004480 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004481{
4482 struct pending_cmd *cmd;
4483 int err;
4484
Johan Hedberg744cf192011-11-08 20:40:14 +02004485 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004486
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004487 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004488 if (!cmd)
4489 return -ENOENT;
4490
4491 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004492 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4493 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004494 } else {
4495 struct mgmt_rp_read_local_oob_data rp;
4496
4497 memcpy(rp.hash, hash, sizeof(rp.hash));
4498 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4499
Johan Hedberg744cf192011-11-08 20:40:14 +02004500 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004501 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4502 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004503 }
4504
4505 mgmt_pending_remove(cmd);
4506
4507 return err;
4508}
Johan Hedberge17acd42011-03-30 23:57:16 +03004509
Johan Hedberg48264f02011-11-09 13:58:58 +02004510int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004511 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4512 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004513{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004514 char buf[512];
4515 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004516 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004517
Andre Guedes12602d02013-04-30 15:29:40 -03004518 if (!hci_discovery_active(hdev))
4519 return -EPERM;
4520
Johan Hedberg1dc06092012-01-15 21:01:23 +02004521 /* Leave 5 bytes for a potential CoD field */
4522 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004523 return -EINVAL;
4524
Johan Hedberg1dc06092012-01-15 21:01:23 +02004525 memset(buf, 0, sizeof(buf));
4526
Johan Hedberge319d2e2012-01-15 19:51:59 +02004527 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004528 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004529 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004530 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304531 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004532 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304533 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004534
Johan Hedberg1dc06092012-01-15 21:01:23 +02004535 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004536 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004537
Johan Hedberg1dc06092012-01-15 21:01:23 +02004538 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4539 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004540 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004541
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004542 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004543 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004544
Johan Hedberge319d2e2012-01-15 19:51:59 +02004545 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004546}
Johan Hedberga88a9652011-03-30 13:18:12 +03004547
Johan Hedbergb644ba32012-01-17 21:48:47 +02004548int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004549 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004550{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004551 struct mgmt_ev_device_found *ev;
4552 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4553 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004554
Johan Hedbergb644ba32012-01-17 21:48:47 +02004555 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004556
Johan Hedbergb644ba32012-01-17 21:48:47 +02004557 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004558
Johan Hedbergb644ba32012-01-17 21:48:47 +02004559 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004560 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004561 ev->rssi = rssi;
4562
4563 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004564 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004565
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004566 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004567
Johan Hedberg053c7e02012-02-04 00:06:00 +02004568 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004569 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004570}
Johan Hedberg314b2382011-04-27 10:29:57 -04004571
Johan Hedberg744cf192011-11-08 20:40:14 +02004572int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004573{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004574 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004575 struct pending_cmd *cmd;
4576
Andre Guedes343fb142011-11-22 17:14:19 -03004577 BT_DBG("%s discovering %u", hdev->name, discovering);
4578
Johan Hedberg164a6e72011-11-01 17:06:44 +02004579 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004580 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004581 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004582 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004583
4584 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004585 u8 type = hdev->discovery.type;
4586
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004587 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4588 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004589 mgmt_pending_remove(cmd);
4590 }
4591
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004592 memset(&ev, 0, sizeof(ev));
4593 ev.type = hdev->discovery.type;
4594 ev.discovering = discovering;
4595
4596 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004597}
Antti Julku5e762442011-08-25 16:48:02 +03004598
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004599int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004600{
4601 struct pending_cmd *cmd;
4602 struct mgmt_ev_device_blocked ev;
4603
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004604 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004605
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004606 bacpy(&ev.addr.bdaddr, bdaddr);
4607 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004608
Johan Hedberg744cf192011-11-08 20:40:14 +02004609 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004611}
4612
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004613int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004614{
4615 struct pending_cmd *cmd;
4616 struct mgmt_ev_device_unblocked ev;
4617
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004618 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004619
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004620 bacpy(&ev.addr.bdaddr, bdaddr);
4621 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004622
Johan Hedberg744cf192011-11-08 20:40:14 +02004623 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004624 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004625}