blob: b87163238c1000658674f9051dec3e4962faa5b0 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg2da9c552012-02-17 14:39:28 +020035#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060036#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020037
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070076 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030077 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030078 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070079 MGMT_OP_SET_STATIC_ADDRESS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020080};
81
82static const u16 mgmt_events[] = {
83 MGMT_EV_CONTROLLER_ERROR,
84 MGMT_EV_INDEX_ADDED,
85 MGMT_EV_INDEX_REMOVED,
86 MGMT_EV_NEW_SETTINGS,
87 MGMT_EV_CLASS_OF_DEV_CHANGED,
88 MGMT_EV_LOCAL_NAME_CHANGED,
89 MGMT_EV_NEW_LINK_KEY,
90 MGMT_EV_NEW_LONG_TERM_KEY,
91 MGMT_EV_DEVICE_CONNECTED,
92 MGMT_EV_DEVICE_DISCONNECTED,
93 MGMT_EV_CONNECT_FAILED,
94 MGMT_EV_PIN_CODE_REQUEST,
95 MGMT_EV_USER_CONFIRM_REQUEST,
96 MGMT_EV_USER_PASSKEY_REQUEST,
97 MGMT_EV_AUTH_FAILED,
98 MGMT_EV_DEVICE_FOUND,
99 MGMT_EV_DISCOVERING,
100 MGMT_EV_DEVICE_BLOCKED,
101 MGMT_EV_DEVICE_UNBLOCKED,
102 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300103 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200104};
105
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800106#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200107
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200108#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
109 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
110
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200111struct pending_cmd {
112 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200113 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100115 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300117 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118};
119
Johan Hedbergca69b792011-11-11 18:10:00 +0200120/* HCI to MGMT error code conversion table */
121static u8 mgmt_status_table[] = {
122 MGMT_STATUS_SUCCESS,
123 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
124 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
125 MGMT_STATUS_FAILED, /* Hardware Failure */
126 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
127 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
128 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
129 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
130 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
132 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
133 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
134 MGMT_STATUS_BUSY, /* Command Disallowed */
135 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
136 MGMT_STATUS_REJECTED, /* Rejected Security */
137 MGMT_STATUS_REJECTED, /* Rejected Personal */
138 MGMT_STATUS_TIMEOUT, /* Host Timeout */
139 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
140 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
141 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
142 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
143 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
144 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
145 MGMT_STATUS_BUSY, /* Repeated Attempts */
146 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
147 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
148 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
149 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
150 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
151 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
153 MGMT_STATUS_FAILED, /* Unspecified Error */
154 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
155 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
156 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
157 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
158 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
159 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
160 MGMT_STATUS_FAILED, /* Unit Link Key Used */
161 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
162 MGMT_STATUS_TIMEOUT, /* Instant Passed */
163 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
164 MGMT_STATUS_FAILED, /* Transaction Collision */
165 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
166 MGMT_STATUS_REJECTED, /* QoS Rejected */
167 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
168 MGMT_STATUS_REJECTED, /* Insufficient Security */
169 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
170 MGMT_STATUS_BUSY, /* Role Switch Pending */
171 MGMT_STATUS_FAILED, /* Slot Violation */
172 MGMT_STATUS_FAILED, /* Role Switch Failed */
173 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
174 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
175 MGMT_STATUS_BUSY, /* Host Busy Pairing */
176 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
177 MGMT_STATUS_BUSY, /* Controller Busy */
178 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
179 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
180 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
181 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
182 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
183};
184
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300185bool mgmt_valid_hdev(struct hci_dev *hdev)
186{
187 return hdev->dev_type == HCI_BREDR;
188}
189
Johan Hedbergca69b792011-11-11 18:10:00 +0200190static u8 mgmt_status(u8 hci_status)
191{
192 if (hci_status < ARRAY_SIZE(mgmt_status_table))
193 return mgmt_status_table[hci_status];
194
195 return MGMT_STATUS_FAILED;
196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200199{
200 struct sk_buff *skb;
201 struct mgmt_hdr *hdr;
202 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300203 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204
Szymon Janc34eb5252011-02-28 14:10:08 +0100205 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200206
Andre Guedes790eff42012-06-07 19:05:46 -0300207 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200208 if (!skb)
209 return -ENOMEM;
210
211 hdr = (void *) skb_put(skb, sizeof(*hdr));
212
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530213 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100214 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200215 hdr->len = cpu_to_le16(sizeof(*ev));
216
217 ev = (void *) skb_put(skb, sizeof(*ev));
218 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200219 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300221 err = sock_queue_rcv_skb(sk, skb);
222 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 kfree_skb(skb);
224
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300225 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200226}
227
Johan Hedbergaee9b212012-02-18 15:07:59 +0200228static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300229 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200230{
231 struct sk_buff *skb;
232 struct mgmt_hdr *hdr;
233 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200235
236 BT_DBG("sock %p", sk);
237
Andre Guedes790eff42012-06-07 19:05:46 -0300238 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200239 if (!skb)
240 return -ENOMEM;
241
242 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200243
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530244 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100245 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
Johan Hedberga38528f2011-01-22 06:46:43 +0200248 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200249 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200250 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100251
252 if (rp)
253 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200254
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300255 err = sock_queue_rcv_skb(sk, skb);
256 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200257 kfree_skb(skb);
258
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100259 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200260}
261
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300262static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
263 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200264{
265 struct mgmt_rp_read_version rp;
266
267 BT_DBG("sock %p", sk);
268
269 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200270 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200271
Johan Hedbergaee9b212012-02-18 15:07:59 +0200272 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200274}
275
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300276static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
277 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200278{
279 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200280 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
281 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200282 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283 size_t rp_size;
284 int i, err;
285
286 BT_DBG("sock %p", sk);
287
288 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
289
290 rp = kmalloc(rp_size, GFP_KERNEL);
291 if (!rp)
292 return -ENOMEM;
293
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200294 rp->num_commands = __constant_cpu_to_le16(num_commands);
295 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296
297 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
298 put_unaligned_le16(mgmt_commands[i], opcode);
299
300 for (i = 0; i < num_events; i++, opcode++)
301 put_unaligned_le16(mgmt_events[i], opcode);
302
Johan Hedbergaee9b212012-02-18 15:07:59 +0200303 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300304 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305 kfree(rp);
306
307 return err;
308}
309
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300310static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
311 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200314 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200315 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300317 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318
319 BT_DBG("sock %p", sk);
320
321 read_lock(&hci_dev_list_lock);
322
323 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300324 list_for_each_entry(d, &hci_dev_list, list) {
325 if (!mgmt_valid_hdev(d))
326 continue;
327
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 count++;
329 }
330
Johan Hedberga38528f2011-01-22 06:46:43 +0200331 rp_len = sizeof(*rp) + (2 * count);
332 rp = kmalloc(rp_len, GFP_ATOMIC);
333 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100334 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200335 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100336 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200337
Johan Hedberg476e44c2012-10-19 20:10:46 +0300338 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200339 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200340 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200341 continue;
342
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700343 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
344 continue;
345
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300346 if (!mgmt_valid_hdev(d))
347 continue;
348
Johan Hedberg476e44c2012-10-19 20:10:46 +0300349 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 BT_DBG("Added hci%u", d->id);
351 }
352
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 rp->num_controllers = cpu_to_le16(count);
354 rp_len = sizeof(*rp) + (2 * count);
355
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356 read_unlock(&hci_dev_list_lock);
357
Johan Hedbergaee9b212012-02-18 15:07:59 +0200358 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300359 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
Johan Hedberga38528f2011-01-22 06:46:43 +0200361 kfree(rp);
362
363 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364}
365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200367{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200369
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200371 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200372
Andre Guedes9a1a1992012-07-24 15:03:48 -0300373 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200375
Andre Guedesed3fa312012-07-24 15:03:46 -0300376 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300377 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500378 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
379 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300380 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200381 settings |= MGMT_SETTING_BREDR;
382 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700384 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100385
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300386 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200387 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300388 settings |= MGMT_SETTING_ADVERTISING;
389 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500404 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
405 settings |= MGMT_SETTING_FAST_CONNECTABLE;
406
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200407 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_DISCOVERABLE;
409
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200410 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_PAIRABLE;
412
Johan Hedberg56f87902013-10-02 13:43:13 +0300413 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_BREDR;
415
Johan Hedberg06199cf2012-02-22 16:37:11 +0200416 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg47990ea2012-02-22 11:58:37 +0200419 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200421
Johan Hedberg84bde9d6c2012-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 Hedberg84bde9d6c2012-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 Hedbergbdb6d972012-02-28 06:13:32 +0200923static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300924 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200925{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300926 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200927 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200928 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200929 u8 scan;
930 int err;
931
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200932 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200933
Johan Hedberg56f87902013-10-02 13:43:13 +0300934 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +0300935 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
936 MGMT_STATUS_NOT_SUPPORTED);
937
Johan Hedberga7e80f22013-01-09 16:05:19 +0200938 if (cp->val != 0x00 && cp->val != 0x01)
939 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
940 MGMT_STATUS_INVALID_PARAMS);
941
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700942 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100943 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200944 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300945 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200946
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200948
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200949 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200950 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300951 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200952 goto failed;
953 }
954
955 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300956 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200957 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300958 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200959 goto failed;
960 }
961
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200963 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300964 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200965 goto failed;
966 }
967
968 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200969 bool changed = false;
970
971 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
972 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
973 changed = true;
974 }
975
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200976 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200977 if (err < 0)
978 goto failed;
979
980 if (changed)
981 err = new_settings(hdev, sk);
982
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200983 goto failed;
984 }
985
986 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100987 if (hdev->discov_timeout > 0) {
988 cancel_delayed_work(&hdev->discov_off);
989 hdev->discov_timeout = 0;
990 }
991
992 if (cp->val && timeout > 0) {
993 hdev->discov_timeout = timeout;
994 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
995 msecs_to_jiffies(hdev->discov_timeout * 1000));
996 }
997
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200998 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200999 goto failed;
1000 }
1001
1002 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1003 if (!cmd) {
1004 err = -ENOMEM;
1005 goto failed;
1006 }
1007
1008 scan = SCAN_PAGE;
1009
1010 if (cp->val)
1011 scan |= SCAN_INQUIRY;
1012 else
1013 cancel_delayed_work(&hdev->discov_off);
1014
1015 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1016 if (err < 0)
1017 mgmt_pending_remove(cmd);
1018
Johan Hedberg03811012010-12-08 00:21:06 +02001019 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001020 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001021
1022failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001023 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001024 return err;
1025}
1026
Johan Hedberg406d7802013-03-15 17:07:09 -05001027static void write_fast_connectable(struct hci_request *req, bool enable)
1028{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001029 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001030 struct hci_cp_write_page_scan_activity acp;
1031 u8 type;
1032
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001033 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1034 return;
1035
Johan Hedberg406d7802013-03-15 17:07:09 -05001036 if (enable) {
1037 type = PAGE_SCAN_TYPE_INTERLACED;
1038
1039 /* 160 msec page scan interval */
1040 acp.interval = __constant_cpu_to_le16(0x0100);
1041 } else {
1042 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1043
1044 /* default 1.28 sec page scan */
1045 acp.interval = __constant_cpu_to_le16(0x0800);
1046 }
1047
1048 acp.window = __constant_cpu_to_le16(0x0012);
1049
Johan Hedbergbd98b992013-03-15 17:07:13 -05001050 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1051 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1052 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1053 sizeof(acp), &acp);
1054
1055 if (hdev->page_scan_type != type)
1056 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001057}
1058
Johan Hedberg2b76f452013-03-15 17:07:04 -05001059static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1060{
1061 struct pending_cmd *cmd;
1062
1063 BT_DBG("status 0x%02x", status);
1064
1065 hci_dev_lock(hdev);
1066
1067 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1068 if (!cmd)
1069 goto unlock;
1070
1071 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1072
1073 mgmt_pending_remove(cmd);
1074
1075unlock:
1076 hci_dev_unlock(hdev);
1077}
1078
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001079static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001080 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001081{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001082 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001083 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001084 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001085 u8 scan;
1086 int err;
1087
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001088 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001089
Johan Hedberg56f87902013-10-02 13:43:13 +03001090 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001091 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1092 MGMT_STATUS_NOT_SUPPORTED);
1093
Johan Hedberga7e80f22013-01-09 16:05:19 +02001094 if (cp->val != 0x00 && cp->val != 0x01)
1095 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1096 MGMT_STATUS_INVALID_PARAMS);
1097
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001098 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001099
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001100 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001101 bool changed = false;
1102
1103 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1104 changed = true;
1105
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001106 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001107 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001108 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001109 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1110 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1111 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001112
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001113 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001114 if (err < 0)
1115 goto failed;
1116
1117 if (changed)
1118 err = new_settings(hdev, sk);
1119
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001120 goto failed;
1121 }
1122
1123 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001124 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001125 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001126 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001127 goto failed;
1128 }
1129
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001130 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001131 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001132 goto failed;
1133 }
1134
1135 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1136 if (!cmd) {
1137 err = -ENOMEM;
1138 goto failed;
1139 }
1140
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001141 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001142 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001143 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001144 scan = 0;
1145
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001146 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001147 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001148 cancel_delayed_work(&hdev->discov_off);
1149 }
1150
Johan Hedberg2b76f452013-03-15 17:07:04 -05001151 hci_req_init(&req, hdev);
1152
1153 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1154
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001155 /* If we're going from non-connectable to connectable or
1156 * vice-versa when fast connectable is enabled ensure that fast
1157 * connectable gets disabled. write_fast_connectable won't do
1158 * anything if the page scan parameters are already what they
1159 * should be.
1160 */
1161 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001162 write_fast_connectable(&req, false);
1163
Johan Hedberg2b76f452013-03-15 17:07:04 -05001164 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001165 if (err < 0)
1166 mgmt_pending_remove(cmd);
1167
1168failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001169 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001170 return err;
1171}
1172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001173static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001174 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001175{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001176 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001177 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001179 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001180
Johan Hedberga7e80f22013-01-09 16:05:19 +02001181 if (cp->val != 0x00 && cp->val != 0x01)
1182 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1183 MGMT_STATUS_INVALID_PARAMS);
1184
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001185 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001186
1187 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001188 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001189 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001190 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001191
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001192 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193 if (err < 0)
1194 goto failed;
1195
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001196 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001197
1198failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001199 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001200 return err;
1201}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001202
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001203static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1204 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001205{
1206 struct mgmt_mode *cp = data;
1207 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001208 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001209 int err;
1210
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001211 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001212
Johan Hedberg56f87902013-10-02 13:43:13 +03001213 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001214 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1215 MGMT_STATUS_NOT_SUPPORTED);
1216
Johan Hedberga7e80f22013-01-09 16:05:19 +02001217 if (cp->val != 0x00 && cp->val != 0x01)
1218 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1219 MGMT_STATUS_INVALID_PARAMS);
1220
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001221 hci_dev_lock(hdev);
1222
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001223 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001224 bool changed = false;
1225
1226 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001227 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001228 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1229 changed = true;
1230 }
1231
1232 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1233 if (err < 0)
1234 goto failed;
1235
1236 if (changed)
1237 err = new_settings(hdev, sk);
1238
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001239 goto failed;
1240 }
1241
1242 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001243 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001244 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001245 goto failed;
1246 }
1247
1248 val = !!cp->val;
1249
1250 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1251 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1252 goto failed;
1253 }
1254
1255 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1256 if (!cmd) {
1257 err = -ENOMEM;
1258 goto failed;
1259 }
1260
1261 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1262 if (err < 0) {
1263 mgmt_pending_remove(cmd);
1264 goto failed;
1265 }
1266
1267failed:
1268 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001269 return err;
1270}
1271
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001272static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001273{
1274 struct mgmt_mode *cp = data;
1275 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001276 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001277 int err;
1278
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001279 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001280
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001281 if (!lmp_ssp_capable(hdev))
1282 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1283 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001284
Johan Hedberga7e80f22013-01-09 16:05:19 +02001285 if (cp->val != 0x00 && cp->val != 0x01)
1286 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1287 MGMT_STATUS_INVALID_PARAMS);
1288
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001289 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001290
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001291 val = !!cp->val;
1292
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001293 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001294 bool changed = false;
1295
1296 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1297 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1298 changed = true;
1299 }
1300
1301 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1302 if (err < 0)
1303 goto failed;
1304
1305 if (changed)
1306 err = new_settings(hdev, sk);
1307
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001308 goto failed;
1309 }
1310
1311 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001312 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1313 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001314 goto failed;
1315 }
1316
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001317 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1318 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1319 goto failed;
1320 }
1321
1322 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1323 if (!cmd) {
1324 err = -ENOMEM;
1325 goto failed;
1326 }
1327
1328 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1329 if (err < 0) {
1330 mgmt_pending_remove(cmd);
1331 goto failed;
1332 }
1333
1334failed:
1335 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001336 return err;
1337}
1338
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001339static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001340{
1341 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001342 bool changed;
1343 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001344
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001345 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001346
Johan Hedberg56f87902013-10-02 13:43:13 +03001347 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001348 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001349 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001350
Johan Hedberga7e80f22013-01-09 16:05:19 +02001351 if (cp->val != 0x00 && cp->val != 0x01)
1352 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1353 MGMT_STATUS_INVALID_PARAMS);
1354
Marcel Holtmannee392692013-10-01 22:59:23 -07001355 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001356
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001357 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001358 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001359 } else {
1360 if (hdev_is_powered(hdev)) {
1361 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1362 MGMT_STATUS_REJECTED);
1363 goto unlock;
1364 }
1365
Marcel Holtmannee392692013-10-01 22:59:23 -07001366 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001367 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001368
1369 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1370 if (err < 0)
1371 goto unlock;
1372
1373 if (changed)
1374 err = new_settings(hdev, sk);
1375
1376unlock:
1377 hci_dev_unlock(hdev);
1378 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001379}
1380
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001381static void le_enable_complete(struct hci_dev *hdev, u8 status)
1382{
1383 struct cmd_lookup match = { NULL, hdev };
1384
1385 if (status) {
1386 u8 mgmt_err = mgmt_status(status);
1387
1388 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1389 &mgmt_err);
1390 return;
1391 }
1392
1393 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1394
1395 new_settings(hdev, match.sk);
1396
1397 if (match.sk)
1398 sock_put(match.sk);
1399}
1400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001401static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001402{
1403 struct mgmt_mode *cp = data;
1404 struct hci_cp_write_le_host_supported hci_cp;
1405 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001406 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001407 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001408 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001410 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001411
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001412 if (!lmp_le_capable(hdev))
1413 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1414 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001415
Johan Hedberga7e80f22013-01-09 16:05:19 +02001416 if (cp->val != 0x00 && cp->val != 0x01)
1417 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1418 MGMT_STATUS_INVALID_PARAMS);
1419
Johan Hedbergc73eee92013-04-19 18:35:21 +03001420 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001421 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001422 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1423 MGMT_STATUS_REJECTED);
1424
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001425 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001426
1427 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001428 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001429
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001430 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001431 bool changed = false;
1432
1433 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1434 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1435 changed = true;
1436 }
1437
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001438 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1439 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1440 changed = true;
1441 }
1442
Johan Hedberg06199cf2012-02-22 16:37:11 +02001443 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1444 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001445 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001446
1447 if (changed)
1448 err = new_settings(hdev, sk);
1449
Johan Hedberg1de028c2012-02-29 19:55:35 -08001450 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001451 }
1452
Johan Hedberg4375f102013-09-25 13:26:10 +03001453 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1454 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001455 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001456 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001457 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001458 }
1459
1460 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1461 if (!cmd) {
1462 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001463 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001464 }
1465
1466 memset(&hci_cp, 0, sizeof(hci_cp));
1467
1468 if (val) {
1469 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001470 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001471 }
1472
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001473 hci_req_init(&req, hdev);
1474
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001475 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1476 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1477
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001478 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1479 &hci_cp);
1480
1481 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301482 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001483 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001484
Johan Hedberg1de028c2012-02-29 19:55:35 -08001485unlock:
1486 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001487 return err;
1488}
1489
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001490/* This is a helper function to test for pending mgmt commands that can
1491 * cause CoD or EIR HCI commands. We can only allow one such pending
1492 * mgmt command at a time since otherwise we cannot easily track what
1493 * the current values are, will be, and based on that calculate if a new
1494 * HCI command needs to be sent and if yes with what value.
1495 */
1496static bool pending_eir_or_class(struct hci_dev *hdev)
1497{
1498 struct pending_cmd *cmd;
1499
1500 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1501 switch (cmd->opcode) {
1502 case MGMT_OP_ADD_UUID:
1503 case MGMT_OP_REMOVE_UUID:
1504 case MGMT_OP_SET_DEV_CLASS:
1505 case MGMT_OP_SET_POWERED:
1506 return true;
1507 }
1508 }
1509
1510 return false;
1511}
1512
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001513static const u8 bluetooth_base_uuid[] = {
1514 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1515 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1516};
1517
1518static u8 get_uuid_size(const u8 *uuid)
1519{
1520 u32 val;
1521
1522 if (memcmp(uuid, bluetooth_base_uuid, 12))
1523 return 128;
1524
1525 val = get_unaligned_le32(&uuid[12]);
1526 if (val > 0xffff)
1527 return 32;
1528
1529 return 16;
1530}
1531
Johan Hedberg92da6092013-03-15 17:06:55 -05001532static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1533{
1534 struct pending_cmd *cmd;
1535
1536 hci_dev_lock(hdev);
1537
1538 cmd = mgmt_pending_find(mgmt_op, hdev);
1539 if (!cmd)
1540 goto unlock;
1541
1542 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1543 hdev->dev_class, 3);
1544
1545 mgmt_pending_remove(cmd);
1546
1547unlock:
1548 hci_dev_unlock(hdev);
1549}
1550
1551static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1552{
1553 BT_DBG("status 0x%02x", status);
1554
1555 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1556}
1557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001558static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001559{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001560 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001561 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001562 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001563 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001564 int err;
1565
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001566 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001567
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001568 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001569
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001570 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001571 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001572 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001573 goto failed;
1574 }
1575
Andre Guedes92c4c202012-06-07 19:05:44 -03001576 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001577 if (!uuid) {
1578 err = -ENOMEM;
1579 goto failed;
1580 }
1581
1582 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001583 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001584 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001585
Johan Hedbergde66aa62013-01-27 00:31:27 +02001586 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001587
Johan Hedberg890ea892013-03-15 17:06:52 -05001588 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001589
Johan Hedberg890ea892013-03-15 17:06:52 -05001590 update_class(&req);
1591 update_eir(&req);
1592
Johan Hedberg92da6092013-03-15 17:06:55 -05001593 err = hci_req_run(&req, add_uuid_complete);
1594 if (err < 0) {
1595 if (err != -ENODATA)
1596 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001597
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001598 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001599 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001600 goto failed;
1601 }
1602
1603 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001604 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001605 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001606 goto failed;
1607 }
1608
1609 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001610
1611failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001612 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001613 return err;
1614}
1615
Johan Hedberg24b78d02012-02-23 23:24:30 +02001616static bool enable_service_cache(struct hci_dev *hdev)
1617{
1618 if (!hdev_is_powered(hdev))
1619 return false;
1620
1621 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001622 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1623 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001624 return true;
1625 }
1626
1627 return false;
1628}
1629
Johan Hedberg92da6092013-03-15 17:06:55 -05001630static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1631{
1632 BT_DBG("status 0x%02x", status);
1633
1634 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1635}
1636
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001637static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001638 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001639{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001640 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001641 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001642 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001643 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 -05001644 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001645 int err, found;
1646
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001647 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001648
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001649 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001650
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001651 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001652 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001653 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001654 goto unlock;
1655 }
1656
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001657 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1658 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001659
Johan Hedberg24b78d02012-02-23 23:24:30 +02001660 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001661 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001662 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001663 goto unlock;
1664 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001665
Johan Hedberg9246a862012-02-23 21:33:16 +02001666 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001667 }
1668
1669 found = 0;
1670
Johan Hedberg056341c2013-01-27 00:31:30 +02001671 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001672 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1673 continue;
1674
1675 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001676 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001677 found++;
1678 }
1679
1680 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001681 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001682 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001683 goto unlock;
1684 }
1685
Johan Hedberg9246a862012-02-23 21:33:16 +02001686update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001687 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001688
Johan Hedberg890ea892013-03-15 17:06:52 -05001689 update_class(&req);
1690 update_eir(&req);
1691
Johan Hedberg92da6092013-03-15 17:06:55 -05001692 err = hci_req_run(&req, remove_uuid_complete);
1693 if (err < 0) {
1694 if (err != -ENODATA)
1695 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001696
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001697 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001698 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001699 goto unlock;
1700 }
1701
1702 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001703 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001704 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001705 goto unlock;
1706 }
1707
1708 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001709
1710unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001711 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001712 return err;
1713}
1714
Johan Hedberg92da6092013-03-15 17:06:55 -05001715static void set_class_complete(struct hci_dev *hdev, u8 status)
1716{
1717 BT_DBG("status 0x%02x", status);
1718
1719 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1720}
1721
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001722static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001723 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001724{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001725 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001726 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001727 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001728 int err;
1729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001730 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001731
Johan Hedberg56f87902013-10-02 13:43:13 +03001732 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001733 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1734 MGMT_STATUS_NOT_SUPPORTED);
1735
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001736 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001737
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001738 if (pending_eir_or_class(hdev)) {
1739 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1740 MGMT_STATUS_BUSY);
1741 goto unlock;
1742 }
1743
1744 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1745 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1746 MGMT_STATUS_INVALID_PARAMS);
1747 goto unlock;
1748 }
1749
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001750 hdev->major_class = cp->major;
1751 hdev->minor_class = cp->minor;
1752
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001753 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001754 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001755 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001756 goto unlock;
1757 }
1758
Johan Hedberg890ea892013-03-15 17:06:52 -05001759 hci_req_init(&req, hdev);
1760
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001761 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001762 hci_dev_unlock(hdev);
1763 cancel_delayed_work_sync(&hdev->service_cache);
1764 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001765 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001766 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001767
Johan Hedberg890ea892013-03-15 17:06:52 -05001768 update_class(&req);
1769
Johan Hedberg92da6092013-03-15 17:06:55 -05001770 err = hci_req_run(&req, set_class_complete);
1771 if (err < 0) {
1772 if (err != -ENODATA)
1773 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001774
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001775 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001776 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001777 goto unlock;
1778 }
1779
1780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001781 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001782 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001783 goto unlock;
1784 }
1785
1786 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001787
Johan Hedbergb5235a62012-02-21 14:32:24 +02001788unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001789 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001790 return err;
1791}
1792
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001793static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001794 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001795{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001796 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001797 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001798 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001799
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001800 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001801
Johan Hedberg86742e12011-11-07 23:13:38 +02001802 expected_len = sizeof(*cp) + key_count *
1803 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001804 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001805 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001806 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001807 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001808 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001809 }
1810
Johan Hedberg4ae14302013-01-20 14:27:13 +02001811 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1812 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1813 MGMT_STATUS_INVALID_PARAMS);
1814
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001815 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001816 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001817
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001818 for (i = 0; i < key_count; i++) {
1819 struct mgmt_link_key_info *key = &cp->keys[i];
1820
1821 if (key->addr.type != BDADDR_BREDR)
1822 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1823 MGMT_STATUS_INVALID_PARAMS);
1824 }
1825
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001826 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001827
1828 hci_link_keys_clear(hdev);
1829
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001830 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001831 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001832 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001833 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001834
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001835 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001836 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001837
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001838 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001839 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001840 }
1841
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001842 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001843
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001844 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001845
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001846 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001847}
1848
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001849static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001850 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001851{
1852 struct mgmt_ev_device_unpaired ev;
1853
1854 bacpy(&ev.addr.bdaddr, bdaddr);
1855 ev.addr.type = addr_type;
1856
1857 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001858 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001859}
1860
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001861static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001862 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001863{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001864 struct mgmt_cp_unpair_device *cp = data;
1865 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001866 struct hci_cp_disconnect dc;
1867 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001868 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001869 int err;
1870
Johan Hedberga8a1d192011-11-10 15:54:38 +02001871 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001872 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1873 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001874
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001875 if (!bdaddr_type_is_valid(cp->addr.type))
1876 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1877 MGMT_STATUS_INVALID_PARAMS,
1878 &rp, sizeof(rp));
1879
Johan Hedberg118da702013-01-20 14:27:20 +02001880 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1881 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1882 MGMT_STATUS_INVALID_PARAMS,
1883 &rp, sizeof(rp));
1884
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001885 hci_dev_lock(hdev);
1886
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001887 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001888 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001889 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001890 goto unlock;
1891 }
1892
Andre Guedes591f47f2012-04-24 21:02:49 -03001893 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001894 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1895 else
1896 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001897
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001898 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001899 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001900 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001901 goto unlock;
1902 }
1903
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001904 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001905 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001906 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001907 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001908 else
1909 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001910 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001911 } else {
1912 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001913 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001914
Johan Hedberga8a1d192011-11-10 15:54:38 +02001915 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001916 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001917 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001918 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001919 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001920 }
1921
Johan Hedberg124f6e32012-02-09 13:50:12 +02001922 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001923 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001924 if (!cmd) {
1925 err = -ENOMEM;
1926 goto unlock;
1927 }
1928
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001929 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001930 dc.reason = 0x13; /* Remote User Terminated Connection */
1931 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1932 if (err < 0)
1933 mgmt_pending_remove(cmd);
1934
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001935unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001936 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001937 return err;
1938}
1939
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001940static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001941 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001942{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001943 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001944 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001945 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001946 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001947 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001948 int err;
1949
1950 BT_DBG("");
1951
Johan Hedberg06a63b12013-01-20 14:27:21 +02001952 memset(&rp, 0, sizeof(rp));
1953 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1954 rp.addr.type = cp->addr.type;
1955
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001956 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001957 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1958 MGMT_STATUS_INVALID_PARAMS,
1959 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001960
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001961 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001962
1963 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001964 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1965 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001966 goto failed;
1967 }
1968
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001969 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001970 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1971 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001972 goto failed;
1973 }
1974
Andre Guedes591f47f2012-04-24 21:02:49 -03001975 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001976 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1977 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001978 else
1979 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001980
Vishal Agarwalf9607272012-06-13 05:32:43 +05301981 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001982 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1983 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001984 goto failed;
1985 }
1986
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001987 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001988 if (!cmd) {
1989 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001990 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001991 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001992
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001993 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001994 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001995
1996 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1997 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001998 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001999
2000failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002001 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002002 return err;
2003}
2004
Andre Guedes57c14772012-04-24 21:02:50 -03002005static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002006{
2007 switch (link_type) {
2008 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002009 switch (addr_type) {
2010 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002011 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002012
Johan Hedberg48264f02011-11-09 13:58:58 +02002013 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002014 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002015 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002016 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002017
Johan Hedberg4c659c32011-11-07 23:13:39 +02002018 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002019 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002020 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002021 }
2022}
2023
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002024static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2025 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002026{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002027 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002028 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002029 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002030 int err;
2031 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002032
2033 BT_DBG("");
2034
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002035 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002036
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002037 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002038 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002039 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002040 goto unlock;
2041 }
2042
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002043 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002044 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2045 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002046 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002047 }
2048
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002049 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002050 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002051 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002052 err = -ENOMEM;
2053 goto unlock;
2054 }
2055
Johan Hedberg2784eb42011-01-21 13:56:35 +02002056 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002057 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002058 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2059 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002060 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002061 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002062 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002063 continue;
2064 i++;
2065 }
2066
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002067 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002068
Johan Hedberg4c659c32011-11-07 23:13:39 +02002069 /* Recalculate length in case of filtered SCO connections, etc */
2070 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002071
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002072 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002073 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002074
Johan Hedberga38528f2011-01-22 06:46:43 +02002075 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002076
2077unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002078 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002079 return err;
2080}
2081
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002082static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002083 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002084{
2085 struct pending_cmd *cmd;
2086 int err;
2087
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002088 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002089 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002090 if (!cmd)
2091 return -ENOMEM;
2092
Johan Hedbergd8457692012-02-17 14:24:57 +02002093 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002094 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002095 if (err < 0)
2096 mgmt_pending_remove(cmd);
2097
2098 return err;
2099}
2100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002101static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002102 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002103{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002104 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002105 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002106 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002107 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002108 int err;
2109
2110 BT_DBG("");
2111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002113
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002114 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002115 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002116 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002117 goto failed;
2118 }
2119
Johan Hedbergd8457692012-02-17 14:24:57 +02002120 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002121 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002122 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002123 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002124 goto failed;
2125 }
2126
2127 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002128 struct mgmt_cp_pin_code_neg_reply ncp;
2129
2130 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002131
2132 BT_ERR("PIN code is not 16 bytes long");
2133
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002134 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002135 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002136 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002137 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002138
2139 goto failed;
2140 }
2141
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002142 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002143 if (!cmd) {
2144 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002146 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002147
Johan Hedbergd8457692012-02-17 14:24:57 +02002148 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002149 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002150 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002151
2152 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2153 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002154 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002155
2156failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002157 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002158 return err;
2159}
2160
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002161static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2162 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002163{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002164 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002165
2166 BT_DBG("");
2167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002168 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002169
2170 hdev->io_capability = cp->io_capability;
2171
2172 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002173 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002174
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002175 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002176
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002177 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2178 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002179}
2180
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002181static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002182{
2183 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002184 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002185
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002186 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002187 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2188 continue;
2189
Johan Hedberge9a416b2011-02-19 12:05:56 -03002190 if (cmd->user_data != conn)
2191 continue;
2192
2193 return cmd;
2194 }
2195
2196 return NULL;
2197}
2198
2199static void pairing_complete(struct pending_cmd *cmd, u8 status)
2200{
2201 struct mgmt_rp_pair_device rp;
2202 struct hci_conn *conn = cmd->user_data;
2203
Johan Hedbergba4e5642011-11-11 00:07:34 +02002204 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002205 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002206
Johan Hedbergaee9b212012-02-18 15:07:59 +02002207 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002208 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002209
2210 /* So we don't get further callbacks for this connection */
2211 conn->connect_cfm_cb = NULL;
2212 conn->security_cfm_cb = NULL;
2213 conn->disconn_cfm_cb = NULL;
2214
David Herrmann76a68ba2013-04-06 20:28:37 +02002215 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002216
Johan Hedberga664b5b2011-02-19 12:06:02 -03002217 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002218}
2219
2220static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2221{
2222 struct pending_cmd *cmd;
2223
2224 BT_DBG("status %u", status);
2225
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002226 cmd = find_pairing(conn);
2227 if (!cmd)
2228 BT_DBG("Unable to find a pending command");
2229 else
Johan Hedberge2113262012-02-18 15:20:03 +02002230 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002231}
2232
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302233static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2234{
2235 struct pending_cmd *cmd;
2236
2237 BT_DBG("status %u", status);
2238
2239 if (!status)
2240 return;
2241
2242 cmd = find_pairing(conn);
2243 if (!cmd)
2244 BT_DBG("Unable to find a pending command");
2245 else
2246 pairing_complete(cmd, mgmt_status(status));
2247}
2248
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002249static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002250 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002251{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002252 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002253 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002254 struct pending_cmd *cmd;
2255 u8 sec_level, auth_type;
2256 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002257 int err;
2258
2259 BT_DBG("");
2260
Szymon Jancf950a30e2013-01-18 12:48:07 +01002261 memset(&rp, 0, sizeof(rp));
2262 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2263 rp.addr.type = cp->addr.type;
2264
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002265 if (!bdaddr_type_is_valid(cp->addr.type))
2266 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2267 MGMT_STATUS_INVALID_PARAMS,
2268 &rp, sizeof(rp));
2269
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002270 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002271
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002272 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002273 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2274 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002275 goto unlock;
2276 }
2277
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002278 sec_level = BT_SECURITY_MEDIUM;
2279 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002280 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002281 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002282 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002283
Andre Guedes591f47f2012-04-24 21:02:49 -03002284 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002285 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2286 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002287 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002288 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2289 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002290
Ville Tervo30e76272011-02-22 16:10:53 -03002291 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002292 int status;
2293
2294 if (PTR_ERR(conn) == -EBUSY)
2295 status = MGMT_STATUS_BUSY;
2296 else
2297 status = MGMT_STATUS_CONNECT_FAILED;
2298
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002300 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002301 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002302 goto unlock;
2303 }
2304
2305 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002306 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002307 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002308 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002309 goto unlock;
2310 }
2311
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002312 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002313 if (!cmd) {
2314 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002315 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002316 goto unlock;
2317 }
2318
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002319 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002320 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002321 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302322 else
2323 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002324
Johan Hedberge9a416b2011-02-19 12:05:56 -03002325 conn->security_cfm_cb = pairing_complete_cb;
2326 conn->disconn_cfm_cb = pairing_complete_cb;
2327 conn->io_capability = cp->io_cap;
2328 cmd->user_data = conn;
2329
2330 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002331 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002332 pairing_complete(cmd, 0);
2333
2334 err = 0;
2335
2336unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002337 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002338 return err;
2339}
2340
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002341static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2342 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002343{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002344 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002345 struct pending_cmd *cmd;
2346 struct hci_conn *conn;
2347 int err;
2348
2349 BT_DBG("");
2350
Johan Hedberg28424702012-02-02 04:02:29 +02002351 hci_dev_lock(hdev);
2352
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002353 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002354 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002355 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002356 goto unlock;
2357 }
2358
Johan Hedberg28424702012-02-02 04:02:29 +02002359 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2360 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002361 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002362 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002363 goto unlock;
2364 }
2365
2366 conn = cmd->user_data;
2367
2368 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002369 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002370 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002371 goto unlock;
2372 }
2373
2374 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2375
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002376 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002377 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002378unlock:
2379 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002380 return err;
2381}
2382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002383static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002384 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002385 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002386{
Johan Hedberga5c29682011-02-19 12:05:57 -03002387 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002388 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002389 int err;
2390
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002391 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002392
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002393 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002394 err = cmd_complete(sk, hdev->id, mgmt_op,
2395 MGMT_STATUS_NOT_POWERED, addr,
2396 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002397 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002398 }
2399
Johan Hedberg1707c602013-03-15 17:07:15 -05002400 if (addr->type == BDADDR_BREDR)
2401 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002402 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002403 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002404
Johan Hedberg272d90d2012-02-09 15:26:12 +02002405 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002406 err = cmd_complete(sk, hdev->id, mgmt_op,
2407 MGMT_STATUS_NOT_CONNECTED, addr,
2408 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002409 goto done;
2410 }
2411
Johan Hedberg1707c602013-03-15 17:07:15 -05002412 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002413 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002414 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002415
Brian Gix5fe57d92011-12-21 16:12:13 -08002416 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002417 err = cmd_complete(sk, hdev->id, mgmt_op,
2418 MGMT_STATUS_SUCCESS, addr,
2419 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002420 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002421 err = cmd_complete(sk, hdev->id, mgmt_op,
2422 MGMT_STATUS_FAILED, addr,
2423 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002424
Brian Gix47c15e22011-11-16 13:53:14 -08002425 goto done;
2426 }
2427
Johan Hedberg1707c602013-03-15 17:07:15 -05002428 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002429 if (!cmd) {
2430 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002431 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002432 }
2433
Brian Gix0df4c182011-11-16 13:53:13 -08002434 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002435 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2436 struct hci_cp_user_passkey_reply cp;
2437
Johan Hedberg1707c602013-03-15 17:07:15 -05002438 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002439 cp.passkey = passkey;
2440 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2441 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002442 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2443 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002444
Johan Hedberga664b5b2011-02-19 12:06:02 -03002445 if (err < 0)
2446 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002447
Brian Gix0df4c182011-11-16 13:53:13 -08002448done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002449 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002450 return err;
2451}
2452
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302453static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2454 void *data, u16 len)
2455{
2456 struct mgmt_cp_pin_code_neg_reply *cp = data;
2457
2458 BT_DBG("");
2459
Johan Hedberg1707c602013-03-15 17:07:15 -05002460 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302461 MGMT_OP_PIN_CODE_NEG_REPLY,
2462 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2463}
2464
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002465static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2466 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002467{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002468 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002469
2470 BT_DBG("");
2471
2472 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002473 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002474 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002475
Johan Hedberg1707c602013-03-15 17:07:15 -05002476 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002477 MGMT_OP_USER_CONFIRM_REPLY,
2478 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002479}
2480
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002481static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002482 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002483{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002484 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002485
2486 BT_DBG("");
2487
Johan Hedberg1707c602013-03-15 17:07:15 -05002488 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002489 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2490 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002491}
2492
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002493static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2494 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002495{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002496 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002497
2498 BT_DBG("");
2499
Johan Hedberg1707c602013-03-15 17:07:15 -05002500 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002501 MGMT_OP_USER_PASSKEY_REPLY,
2502 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002503}
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002508 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002509
2510 BT_DBG("");
2511
Johan Hedberg1707c602013-03-15 17:07:15 -05002512 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002513 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2514 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002515}
2516
Johan Hedberg13928972013-03-15 17:07:00 -05002517static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002518{
Johan Hedberg13928972013-03-15 17:07:00 -05002519 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002520 struct hci_cp_write_local_name cp;
2521
Johan Hedberg13928972013-03-15 17:07:00 -05002522 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002523
Johan Hedberg890ea892013-03-15 17:06:52 -05002524 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002525}
2526
Johan Hedberg13928972013-03-15 17:07:00 -05002527static void set_name_complete(struct hci_dev *hdev, u8 status)
2528{
2529 struct mgmt_cp_set_local_name *cp;
2530 struct pending_cmd *cmd;
2531
2532 BT_DBG("status 0x%02x", status);
2533
2534 hci_dev_lock(hdev);
2535
2536 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2537 if (!cmd)
2538 goto unlock;
2539
2540 cp = cmd->param;
2541
2542 if (status)
2543 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2544 mgmt_status(status));
2545 else
2546 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2547 cp, sizeof(*cp));
2548
2549 mgmt_pending_remove(cmd);
2550
2551unlock:
2552 hci_dev_unlock(hdev);
2553}
2554
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002555static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002556 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002557{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002558 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002559 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002560 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002561 int err;
2562
2563 BT_DBG("");
2564
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002565 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002566
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002567 /* If the old values are the same as the new ones just return a
2568 * direct command complete event.
2569 */
2570 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2571 !memcmp(hdev->short_name, cp->short_name,
2572 sizeof(hdev->short_name))) {
2573 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2574 data, len);
2575 goto failed;
2576 }
2577
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002578 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002579
Johan Hedbergb5235a62012-02-21 14:32:24 +02002580 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002581 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002582
2583 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002584 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002585 if (err < 0)
2586 goto failed;
2587
2588 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002589 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002590
Johan Hedbergb5235a62012-02-21 14:32:24 +02002591 goto failed;
2592 }
2593
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002594 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002595 if (!cmd) {
2596 err = -ENOMEM;
2597 goto failed;
2598 }
2599
Johan Hedberg13928972013-03-15 17:07:00 -05002600 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2601
Johan Hedberg890ea892013-03-15 17:06:52 -05002602 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002603
2604 if (lmp_bredr_capable(hdev)) {
2605 update_name(&req);
2606 update_eir(&req);
2607 }
2608
2609 if (lmp_le_capable(hdev))
2610 hci_update_ad(&req);
2611
Johan Hedberg13928972013-03-15 17:07:00 -05002612 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002613 if (err < 0)
2614 mgmt_pending_remove(cmd);
2615
2616failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002617 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002618 return err;
2619}
2620
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002621static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002622 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002623{
Szymon Jancc35938b2011-03-22 13:12:21 +01002624 struct pending_cmd *cmd;
2625 int err;
2626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002627 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002629 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002630
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002631 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002632 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002633 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002634 goto unlock;
2635 }
2636
Andre Guedes9a1a1992012-07-24 15:03:48 -03002637 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002638 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002639 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002640 goto unlock;
2641 }
2642
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002643 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002646 goto unlock;
2647 }
2648
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002649 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002650 if (!cmd) {
2651 err = -ENOMEM;
2652 goto unlock;
2653 }
2654
2655 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2656 if (err < 0)
2657 mgmt_pending_remove(cmd);
2658
2659unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002660 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002661 return err;
2662}
2663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002664static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002665 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002666{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002667 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002668 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002669 int err;
2670
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002671 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002672
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002673 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002674
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002675 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002676 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002677 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002678 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002679 else
Szymon Janca6785be2012-12-13 15:11:21 +01002680 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002681
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002682 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002683 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002684
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002685 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002686 return err;
2687}
2688
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002689static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002690 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002691{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002692 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002693 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002694 int err;
2695
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002696 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002697
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002698 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002699
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002700 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002701 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002702 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002703 else
Szymon Janca6785be2012-12-13 15:11:21 +01002704 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002705
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002706 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002707 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002708
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002709 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002710 return err;
2711}
2712
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002713static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2714{
2715 struct pending_cmd *cmd;
2716 u8 type;
2717 int err;
2718
2719 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2720
2721 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2722 if (!cmd)
2723 return -ENOENT;
2724
2725 type = hdev->discovery.type;
2726
2727 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2728 &type, sizeof(type));
2729 mgmt_pending_remove(cmd);
2730
2731 return err;
2732}
2733
Andre Guedes7c307722013-04-30 15:29:28 -03002734static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2735{
2736 BT_DBG("status %d", status);
2737
2738 if (status) {
2739 hci_dev_lock(hdev);
2740 mgmt_start_discovery_failed(hdev, status);
2741 hci_dev_unlock(hdev);
2742 return;
2743 }
2744
2745 hci_dev_lock(hdev);
2746 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2747 hci_dev_unlock(hdev);
2748
2749 switch (hdev->discovery.type) {
2750 case DISCOV_TYPE_LE:
2751 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002752 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002753 break;
2754
2755 case DISCOV_TYPE_INTERLEAVED:
2756 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002757 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002758 break;
2759
2760 case DISCOV_TYPE_BREDR:
2761 break;
2762
2763 default:
2764 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2765 }
2766}
2767
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002768static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002769 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002770{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002771 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002772 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002773 struct hci_cp_le_set_scan_param param_cp;
2774 struct hci_cp_le_set_scan_enable enable_cp;
2775 struct hci_cp_inquiry inq_cp;
2776 struct hci_request req;
2777 /* General inquiry access code (GIAC) */
2778 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002779 int err;
2780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002781 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002782
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002783 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002784
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002785 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002786 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002787 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002788 goto failed;
2789 }
2790
Andre Guedes642be6c2012-03-21 00:03:37 -03002791 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2792 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2793 MGMT_STATUS_BUSY);
2794 goto failed;
2795 }
2796
Johan Hedbergff9ef572012-01-04 14:23:45 +02002797 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002798 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002799 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002800 goto failed;
2801 }
2802
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002803 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002804 if (!cmd) {
2805 err = -ENOMEM;
2806 goto failed;
2807 }
2808
Andre Guedes4aab14e2012-02-17 20:39:36 -03002809 hdev->discovery.type = cp->type;
2810
Andre Guedes7c307722013-04-30 15:29:28 -03002811 hci_req_init(&req, hdev);
2812
Andre Guedes4aab14e2012-02-17 20:39:36 -03002813 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002814 case DISCOV_TYPE_BREDR:
Johan Hedberg56f87902013-10-02 13:43:13 +03002815 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002816 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2817 MGMT_STATUS_NOT_SUPPORTED);
2818 mgmt_pending_remove(cmd);
2819 goto failed;
2820 }
2821
Andre Guedes7c307722013-04-30 15:29:28 -03002822 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2823 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2824 MGMT_STATUS_BUSY);
2825 mgmt_pending_remove(cmd);
2826 goto failed;
2827 }
2828
2829 hci_inquiry_cache_flush(hdev);
2830
2831 memset(&inq_cp, 0, sizeof(inq_cp));
2832 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002833 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002834 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002835 break;
2836
2837 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002838 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002839 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002840 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2841 MGMT_STATUS_NOT_SUPPORTED);
2842 mgmt_pending_remove(cmd);
2843 goto failed;
2844 }
2845
Andre Guedes7c307722013-04-30 15:29:28 -03002846 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002847 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002848 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2849 MGMT_STATUS_NOT_SUPPORTED);
2850 mgmt_pending_remove(cmd);
2851 goto failed;
2852 }
2853
Andre Guedes7c307722013-04-30 15:29:28 -03002854 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2855 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2856 MGMT_STATUS_REJECTED);
2857 mgmt_pending_remove(cmd);
2858 goto failed;
2859 }
2860
2861 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2862 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2863 MGMT_STATUS_BUSY);
2864 mgmt_pending_remove(cmd);
2865 goto failed;
2866 }
2867
2868 memset(&param_cp, 0, sizeof(param_cp));
2869 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002870 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2871 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002872 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2873 &param_cp);
2874
2875 memset(&enable_cp, 0, sizeof(enable_cp));
2876 enable_cp.enable = LE_SCAN_ENABLE;
2877 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2878 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2879 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002880 break;
2881
Andre Guedesf39799f2012-02-17 20:39:35 -03002882 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002883 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2884 MGMT_STATUS_INVALID_PARAMS);
2885 mgmt_pending_remove(cmd);
2886 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002887 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002888
Andre Guedes7c307722013-04-30 15:29:28 -03002889 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002890 if (err < 0)
2891 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002892 else
2893 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002894
2895failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002896 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002897 return err;
2898}
2899
Andre Guedes1183fdc2013-04-30 15:29:35 -03002900static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2901{
2902 struct pending_cmd *cmd;
2903 int err;
2904
2905 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2906 if (!cmd)
2907 return -ENOENT;
2908
2909 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2910 &hdev->discovery.type, sizeof(hdev->discovery.type));
2911 mgmt_pending_remove(cmd);
2912
2913 return err;
2914}
2915
Andre Guedes0e05bba2013-04-30 15:29:33 -03002916static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2917{
2918 BT_DBG("status %d", status);
2919
2920 hci_dev_lock(hdev);
2921
2922 if (status) {
2923 mgmt_stop_discovery_failed(hdev, status);
2924 goto unlock;
2925 }
2926
2927 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2928
2929unlock:
2930 hci_dev_unlock(hdev);
2931}
2932
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002933static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002934 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002935{
Johan Hedbergd9306502012-02-20 23:25:18 +02002936 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002937 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002938 struct hci_cp_remote_name_req_cancel cp;
2939 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002940 struct hci_request req;
2941 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002942 int err;
2943
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002944 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002945
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002946 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002947
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002948 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002949 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002950 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2951 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002952 goto unlock;
2953 }
2954
2955 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002956 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2958 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002959 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002960 }
2961
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002962 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002963 if (!cmd) {
2964 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002965 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002966 }
2967
Andre Guedes0e05bba2013-04-30 15:29:33 -03002968 hci_req_init(&req, hdev);
2969
Andre Guedese0d9727e2012-03-20 15:15:36 -03002970 switch (hdev->discovery.state) {
2971 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002972 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2973 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2974 } else {
2975 cancel_delayed_work(&hdev->le_scan_disable);
2976
2977 memset(&enable_cp, 0, sizeof(enable_cp));
2978 enable_cp.enable = LE_SCAN_DISABLE;
2979 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2980 sizeof(enable_cp), &enable_cp);
2981 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002982
Andre Guedese0d9727e2012-03-20 15:15:36 -03002983 break;
2984
2985 case DISCOVERY_RESOLVING:
2986 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002987 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002988 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002989 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002990 err = cmd_complete(sk, hdev->id,
2991 MGMT_OP_STOP_DISCOVERY, 0,
2992 &mgmt_cp->type,
2993 sizeof(mgmt_cp->type));
2994 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2995 goto unlock;
2996 }
2997
2998 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002999 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3000 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003001
3002 break;
3003
3004 default:
3005 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003006
3007 mgmt_pending_remove(cmd);
3008 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3009 MGMT_STATUS_FAILED, &mgmt_cp->type,
3010 sizeof(mgmt_cp->type));
3011 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003012 }
3013
Andre Guedes0e05bba2013-04-30 15:29:33 -03003014 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003015 if (err < 0)
3016 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003017 else
3018 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003019
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003020unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003021 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003022 return err;
3023}
3024
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003025static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003026 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003027{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003028 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003029 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003030 int err;
3031
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003032 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003033
Johan Hedberg561aafb2012-01-04 13:31:59 +02003034 hci_dev_lock(hdev);
3035
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003036 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003037 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003039 goto failed;
3040 }
3041
Johan Hedberga198e7b2012-02-17 14:27:06 +02003042 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003043 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003044 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003045 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003046 goto failed;
3047 }
3048
3049 if (cp->name_known) {
3050 e->name_state = NAME_KNOWN;
3051 list_del(&e->list);
3052 } else {
3053 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003054 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003055 }
3056
Johan Hedberge3846622013-01-09 15:29:33 +02003057 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3058 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003059
3060failed:
3061 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003062 return err;
3063}
3064
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003065static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003066 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003067{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003068 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003069 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003070 int err;
3071
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003072 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003073
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003074 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003075 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3076 MGMT_STATUS_INVALID_PARAMS,
3077 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003078
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003079 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003080
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003081 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003082 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003083 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003084 else
Szymon Janca6785be2012-12-13 15:11:21 +01003085 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003087 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003088 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003089
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003090 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003091
3092 return err;
3093}
3094
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003095static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003096 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003097{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003098 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003099 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003100 int err;
3101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003102 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003103
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003104 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003105 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3106 MGMT_STATUS_INVALID_PARAMS,
3107 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003108
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003109 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003110
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003111 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003112 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003113 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003114 else
Szymon Janca6785be2012-12-13 15:11:21 +01003115 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003116
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003117 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003118 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003120 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003121
3122 return err;
3123}
3124
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003125static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3126 u16 len)
3127{
3128 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003129 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003130 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003131 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003132
3133 BT_DBG("%s", hdev->name);
3134
Szymon Jancc72d4b82012-03-16 16:02:57 +01003135 source = __le16_to_cpu(cp->source);
3136
3137 if (source > 0x0002)
3138 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3139 MGMT_STATUS_INVALID_PARAMS);
3140
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003141 hci_dev_lock(hdev);
3142
Szymon Jancc72d4b82012-03-16 16:02:57 +01003143 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003144 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3145 hdev->devid_product = __le16_to_cpu(cp->product);
3146 hdev->devid_version = __le16_to_cpu(cp->version);
3147
3148 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3149
Johan Hedberg890ea892013-03-15 17:06:52 -05003150 hci_req_init(&req, hdev);
3151 update_eir(&req);
3152 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003153
3154 hci_dev_unlock(hdev);
3155
3156 return err;
3157}
3158
Johan Hedberg4375f102013-09-25 13:26:10 +03003159static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3160{
3161 struct cmd_lookup match = { NULL, hdev };
3162
3163 if (status) {
3164 u8 mgmt_err = mgmt_status(status);
3165
3166 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3167 cmd_status_rsp, &mgmt_err);
3168 return;
3169 }
3170
3171 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3172 &match);
3173
3174 new_settings(hdev, match.sk);
3175
3176 if (match.sk)
3177 sock_put(match.sk);
3178}
3179
3180static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3181{
3182 struct mgmt_mode *cp = data;
3183 struct pending_cmd *cmd;
3184 struct hci_request req;
3185 u8 val, enabled;
3186 int err;
3187
3188 BT_DBG("request for %s", hdev->name);
3189
3190 if (!lmp_le_capable(hdev))
3191 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3192 MGMT_STATUS_NOT_SUPPORTED);
3193
3194 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3195 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3196 MGMT_STATUS_REJECTED);
3197
3198 if (cp->val != 0x00 && cp->val != 0x01)
3199 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3200 MGMT_STATUS_INVALID_PARAMS);
3201
3202 hci_dev_lock(hdev);
3203
3204 val = !!cp->val;
3205 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3206
3207 if (!hdev_is_powered(hdev) || val == enabled) {
3208 bool changed = false;
3209
3210 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3211 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3212 changed = true;
3213 }
3214
3215 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3216 if (err < 0)
3217 goto unlock;
3218
3219 if (changed)
3220 err = new_settings(hdev, sk);
3221
3222 goto unlock;
3223 }
3224
3225 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3226 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3227 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3228 MGMT_STATUS_BUSY);
3229 goto unlock;
3230 }
3231
3232 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3233 if (!cmd) {
3234 err = -ENOMEM;
3235 goto unlock;
3236 }
3237
3238 hci_req_init(&req, hdev);
3239
3240 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3241
3242 err = hci_req_run(&req, set_advertising_complete);
3243 if (err < 0)
3244 mgmt_pending_remove(cmd);
3245
3246unlock:
3247 hci_dev_unlock(hdev);
3248 return err;
3249}
3250
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003251static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3252 void *data, u16 len)
3253{
3254 struct mgmt_cp_set_static_address *cp = data;
3255 int err;
3256
3257 BT_DBG("%s", hdev->name);
3258
3259 if (!lmp_le_capable(hdev))
3260 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3261 MGMT_STATUS_NOT_SUPPORTED);
3262
3263 if (hdev_is_powered(hdev))
3264 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3265 MGMT_STATUS_REJECTED);
3266
3267 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3268 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3269 return cmd_status(sk, hdev->id,
3270 MGMT_OP_SET_STATIC_ADDRESS,
3271 MGMT_STATUS_INVALID_PARAMS);
3272
3273 /* Two most significant bits shall be set */
3274 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3275 return cmd_status(sk, hdev->id,
3276 MGMT_OP_SET_STATIC_ADDRESS,
3277 MGMT_STATUS_INVALID_PARAMS);
3278 }
3279
3280 hci_dev_lock(hdev);
3281
3282 bacpy(&hdev->static_addr, &cp->bdaddr);
3283
3284 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3285
3286 hci_dev_unlock(hdev);
3287
3288 return err;
3289}
3290
Johan Hedberg33e38b32013-03-15 17:07:05 -05003291static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3292{
3293 struct pending_cmd *cmd;
3294
3295 BT_DBG("status 0x%02x", status);
3296
3297 hci_dev_lock(hdev);
3298
3299 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3300 if (!cmd)
3301 goto unlock;
3302
3303 if (status) {
3304 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3305 mgmt_status(status));
3306 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003307 struct mgmt_mode *cp = cmd->param;
3308
3309 if (cp->val)
3310 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3311 else
3312 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3313
Johan Hedberg33e38b32013-03-15 17:07:05 -05003314 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3315 new_settings(hdev, cmd->sk);
3316 }
3317
3318 mgmt_pending_remove(cmd);
3319
3320unlock:
3321 hci_dev_unlock(hdev);
3322}
3323
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003324static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003325 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003326{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003327 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003328 struct pending_cmd *cmd;
3329 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003330 int err;
3331
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003332 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003333
Johan Hedberg56f87902013-10-02 13:43:13 +03003334 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3335 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003336 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3337 MGMT_STATUS_NOT_SUPPORTED);
3338
Johan Hedberga7e80f22013-01-09 16:05:19 +02003339 if (cp->val != 0x00 && cp->val != 0x01)
3340 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3341 MGMT_STATUS_INVALID_PARAMS);
3342
Johan Hedberg5400c042012-02-21 16:40:33 +02003343 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003344 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003345 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003346
3347 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003348 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003349 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003350
3351 hci_dev_lock(hdev);
3352
Johan Hedberg05cbf292013-03-15 17:07:07 -05003353 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3354 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3355 MGMT_STATUS_BUSY);
3356 goto unlock;
3357 }
3358
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003359 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3360 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3361 hdev);
3362 goto unlock;
3363 }
3364
Johan Hedberg33e38b32013-03-15 17:07:05 -05003365 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3366 data, len);
3367 if (!cmd) {
3368 err = -ENOMEM;
3369 goto unlock;
3370 }
3371
3372 hci_req_init(&req, hdev);
3373
Johan Hedberg406d7802013-03-15 17:07:09 -05003374 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003375
3376 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003377 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003378 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003379 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003380 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003381 }
3382
Johan Hedberg33e38b32013-03-15 17:07:05 -05003383unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003384 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003385
Antti Julkuf6422ec2011-06-22 13:11:56 +03003386 return err;
3387}
3388
Johan Hedberg0663ca22013-10-02 13:43:14 +03003389static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3390{
3391 struct pending_cmd *cmd;
3392
3393 BT_DBG("status 0x%02x", status);
3394
3395 hci_dev_lock(hdev);
3396
3397 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3398 if (!cmd)
3399 goto unlock;
3400
3401 if (status) {
3402 u8 mgmt_err = mgmt_status(status);
3403
3404 /* We need to restore the flag if related HCI commands
3405 * failed.
3406 */
3407 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3408
3409 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3410 } else {
3411 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3412 new_settings(hdev, cmd->sk);
3413 }
3414
3415 mgmt_pending_remove(cmd);
3416
3417unlock:
3418 hci_dev_unlock(hdev);
3419}
3420
3421static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3422{
3423 struct mgmt_mode *cp = data;
3424 struct pending_cmd *cmd;
3425 struct hci_request req;
3426 int err;
3427
3428 BT_DBG("request for %s", hdev->name);
3429
3430 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3431 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3432 MGMT_STATUS_NOT_SUPPORTED);
3433
3434 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3435 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3436 MGMT_STATUS_REJECTED);
3437
3438 if (cp->val != 0x00 && cp->val != 0x01)
3439 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3440 MGMT_STATUS_INVALID_PARAMS);
3441
3442 hci_dev_lock(hdev);
3443
3444 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3445 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3446 goto unlock;
3447 }
3448
3449 if (!hdev_is_powered(hdev)) {
3450 if (!cp->val) {
3451 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3452 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3453 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3454 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3455 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3456 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3457 }
3458
3459 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3460
3461 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3462 if (err < 0)
3463 goto unlock;
3464
3465 err = new_settings(hdev, sk);
3466 goto unlock;
3467 }
3468
3469 /* Reject disabling when powered on */
3470 if (!cp->val) {
3471 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3472 MGMT_STATUS_REJECTED);
3473 goto unlock;
3474 }
3475
3476 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3477 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3478 MGMT_STATUS_BUSY);
3479 goto unlock;
3480 }
3481
3482 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3483 if (!cmd) {
3484 err = -ENOMEM;
3485 goto unlock;
3486 }
3487
3488 /* We need to flip the bit already here so that hci_update_ad
3489 * generates the correct flags.
3490 */
3491 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3492
3493 hci_req_init(&req, hdev);
3494 hci_update_ad(&req);
3495 err = hci_req_run(&req, set_bredr_complete);
3496 if (err < 0)
3497 mgmt_pending_remove(cmd);
3498
3499unlock:
3500 hci_dev_unlock(hdev);
3501 return err;
3502}
3503
Johan Hedberg3f706b72013-01-20 14:27:16 +02003504static bool ltk_is_valid(struct mgmt_ltk_info *key)
3505{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003506 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3507 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003508 if (key->master != 0x00 && key->master != 0x01)
3509 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003510 if (!bdaddr_type_is_le(key->addr.type))
3511 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003512 return true;
3513}
3514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003515static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003516 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003517{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003518 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3519 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003520 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003521
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003522 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003523
3524 expected_len = sizeof(*cp) + key_count *
3525 sizeof(struct mgmt_ltk_info);
3526 if (expected_len != len) {
3527 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003528 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003529 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003530 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003531 }
3532
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003533 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003534
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003535 for (i = 0; i < key_count; i++) {
3536 struct mgmt_ltk_info *key = &cp->keys[i];
3537
Johan Hedberg3f706b72013-01-20 14:27:16 +02003538 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003539 return cmd_status(sk, hdev->id,
3540 MGMT_OP_LOAD_LONG_TERM_KEYS,
3541 MGMT_STATUS_INVALID_PARAMS);
3542 }
3543
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003544 hci_dev_lock(hdev);
3545
3546 hci_smp_ltks_clear(hdev);
3547
3548 for (i = 0; i < key_count; i++) {
3549 struct mgmt_ltk_info *key = &cp->keys[i];
3550 u8 type;
3551
3552 if (key->master)
3553 type = HCI_SMP_LTK;
3554 else
3555 type = HCI_SMP_LTK_SLAVE;
3556
Hemant Gupta4596fde2012-04-16 14:57:40 +05303557 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003558 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003559 type, 0, key->authenticated, key->val,
3560 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003561 }
3562
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003563 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3564 NULL, 0);
3565
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003566 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003567
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003568 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003569}
3570
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003571static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003572 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3573 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003574 bool var_len;
3575 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003576} mgmt_handlers[] = {
3577 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003578 { read_version, false, MGMT_READ_VERSION_SIZE },
3579 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3580 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3581 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3582 { set_powered, false, MGMT_SETTING_SIZE },
3583 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3584 { set_connectable, false, MGMT_SETTING_SIZE },
3585 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3586 { set_pairable, false, MGMT_SETTING_SIZE },
3587 { set_link_security, false, MGMT_SETTING_SIZE },
3588 { set_ssp, false, MGMT_SETTING_SIZE },
3589 { set_hs, false, MGMT_SETTING_SIZE },
3590 { set_le, false, MGMT_SETTING_SIZE },
3591 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3592 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3593 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3594 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3595 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3596 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3597 { disconnect, false, MGMT_DISCONNECT_SIZE },
3598 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3599 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3600 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3601 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3602 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3603 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3604 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3605 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3606 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3607 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3608 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3609 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3610 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3611 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3612 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3613 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3614 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3615 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3616 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003617 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003618 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003619 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003620 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003621};
3622
3623
Johan Hedberg03811012010-12-08 00:21:06 +02003624int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3625{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003626 void *buf;
3627 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003628 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003629 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003630 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003631 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003632 int err;
3633
3634 BT_DBG("got %zu bytes", msglen);
3635
3636 if (msglen < sizeof(*hdr))
3637 return -EINVAL;
3638
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003639 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003640 if (!buf)
3641 return -ENOMEM;
3642
3643 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3644 err = -EFAULT;
3645 goto done;
3646 }
3647
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003648 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003649 opcode = __le16_to_cpu(hdr->opcode);
3650 index = __le16_to_cpu(hdr->index);
3651 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003652
3653 if (len != msglen - sizeof(*hdr)) {
3654 err = -EINVAL;
3655 goto done;
3656 }
3657
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003658 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003659 hdev = hci_dev_get(index);
3660 if (!hdev) {
3661 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003662 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003663 goto done;
3664 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003665
3666 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3667 err = cmd_status(sk, index, opcode,
3668 MGMT_STATUS_INVALID_INDEX);
3669 goto done;
3670 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003671 }
3672
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003673 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003674 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003675 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003676 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003677 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003678 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003679 }
3680
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003681 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003682 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003683 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003684 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003685 goto done;
3686 }
3687
Johan Hedbergbe22b542012-03-01 22:24:41 +02003688 handler = &mgmt_handlers[opcode];
3689
3690 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003691 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003692 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003693 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003694 goto done;
3695 }
3696
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003697 if (hdev)
3698 mgmt_init_hdev(sk, hdev);
3699
3700 cp = buf + sizeof(*hdr);
3701
Johan Hedbergbe22b542012-03-01 22:24:41 +02003702 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003703 if (err < 0)
3704 goto done;
3705
Johan Hedberg03811012010-12-08 00:21:06 +02003706 err = msglen;
3707
3708done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003709 if (hdev)
3710 hci_dev_put(hdev);
3711
Johan Hedberg03811012010-12-08 00:21:06 +02003712 kfree(buf);
3713 return err;
3714}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003715
Johan Hedberg744cf192011-11-08 20:40:14 +02003716int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003717{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003718 if (!mgmt_valid_hdev(hdev))
3719 return -ENOTSUPP;
3720
Johan Hedberg744cf192011-11-08 20:40:14 +02003721 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003722}
3723
Johan Hedberg744cf192011-11-08 20:40:14 +02003724int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003725{
Johan Hedberg5f159032012-03-02 03:13:19 +02003726 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003727
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003728 if (!mgmt_valid_hdev(hdev))
3729 return -ENOTSUPP;
3730
Johan Hedberg744cf192011-11-08 20:40:14 +02003731 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003732
Johan Hedberg744cf192011-11-08 20:40:14 +02003733 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003734}
3735
Johan Hedberg890ea892013-03-15 17:06:52 -05003736static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003737{
Johan Hedberg890ea892013-03-15 17:06:52 -05003738 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003739 u8 scan = 0;
3740
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003741 /* Ensure that fast connectable is disabled. This function will
3742 * not do anything if the page scan parameters are already what
3743 * they should be.
3744 */
3745 write_fast_connectable(req, false);
3746
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003747 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3748 scan |= SCAN_PAGE;
3749 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3750 scan |= SCAN_INQUIRY;
3751
Johan Hedberg890ea892013-03-15 17:06:52 -05003752 if (scan)
3753 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003754}
3755
Johan Hedberg229ab392013-03-15 17:06:53 -05003756static void powered_complete(struct hci_dev *hdev, u8 status)
3757{
3758 struct cmd_lookup match = { NULL, hdev };
3759
3760 BT_DBG("status 0x%02x", status);
3761
3762 hci_dev_lock(hdev);
3763
3764 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3765
3766 new_settings(hdev, match.sk);
3767
3768 hci_dev_unlock(hdev);
3769
3770 if (match.sk)
3771 sock_put(match.sk);
3772}
3773
Johan Hedberg70da6242013-03-15 17:06:51 -05003774static int powered_update_hci(struct hci_dev *hdev)
3775{
Johan Hedberg890ea892013-03-15 17:06:52 -05003776 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003777 u8 link_sec;
3778
Johan Hedberg890ea892013-03-15 17:06:52 -05003779 hci_req_init(&req, hdev);
3780
Johan Hedberg70da6242013-03-15 17:06:51 -05003781 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3782 !lmp_host_ssp_capable(hdev)) {
3783 u8 ssp = 1;
3784
Johan Hedberg890ea892013-03-15 17:06:52 -05003785 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003786 }
3787
Johan Hedbergc73eee92013-04-19 18:35:21 +03003788 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3789 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003790 struct hci_cp_write_le_host_supported cp;
3791
3792 cp.le = 1;
3793 cp.simul = lmp_le_br_capable(hdev);
3794
3795 /* Check first if we already have the right
3796 * host state (host features set)
3797 */
3798 if (cp.le != lmp_host_le_capable(hdev) ||
3799 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003800 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3801 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003802
3803 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3804 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003805 }
3806
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003807 if (lmp_le_capable(hdev)) {
3808 /* Set random address to static address if configured */
3809 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3810 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3811 &hdev->static_addr);
3812 }
3813
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003814 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3815 u8 adv = 0x01;
3816
3817 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3818 }
3819
Johan Hedberg70da6242013-03-15 17:06:51 -05003820 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3821 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003822 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3823 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003824
3825 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003826 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3827 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003828 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003829 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003830 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003831 }
3832
Johan Hedberg229ab392013-03-15 17:06:53 -05003833 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003834}
3835
Johan Hedberg744cf192011-11-08 20:40:14 +02003836int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003837{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003838 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003839 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3840 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003841 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003842
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003843 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3844 return 0;
3845
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003846 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003847 if (powered_update_hci(hdev) == 0)
3848 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003849
Johan Hedberg229ab392013-03-15 17:06:53 -05003850 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3851 &match);
3852 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003853 }
3854
Johan Hedberg229ab392013-03-15 17:06:53 -05003855 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3856 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3857
3858 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3859 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3860 zero_cod, sizeof(zero_cod), NULL);
3861
3862new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003863 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003864
3865 if (match.sk)
3866 sock_put(match.sk);
3867
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003868 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003869}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003870
Johan Hedberg96570ff2013-05-29 09:51:29 +03003871int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3872{
3873 struct pending_cmd *cmd;
3874 u8 status;
3875
3876 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3877 if (!cmd)
3878 return -ENOENT;
3879
3880 if (err == -ERFKILL)
3881 status = MGMT_STATUS_RFKILLED;
3882 else
3883 status = MGMT_STATUS_FAILED;
3884
3885 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3886
3887 mgmt_pending_remove(cmd);
3888
3889 return err;
3890}
3891
Johan Hedberg744cf192011-11-08 20:40:14 +02003892int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003893{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003894 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003895 bool changed = false;
3896 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003897
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003898 if (discoverable) {
3899 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3900 changed = true;
3901 } else {
3902 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3903 changed = true;
3904 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003905
Johan Hedberged9b5f22012-02-21 20:47:06 +02003906 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003907 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003908
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003909 if (changed)
3910 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003911
Johan Hedberg73f22f62010-12-29 16:00:25 +02003912 if (match.sk)
3913 sock_put(match.sk);
3914
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003915 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003916}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003917
Johan Hedberg744cf192011-11-08 20:40:14 +02003918int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003919{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003920 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003921 bool changed = false;
3922 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003923
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003924 if (connectable) {
3925 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3926 changed = true;
3927 } else {
3928 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3929 changed = true;
3930 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003931
Johan Hedberg2b76f452013-03-15 17:07:04 -05003932 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003933
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003934 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003935 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003936
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003937 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003938}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003939
Johan Hedberg744cf192011-11-08 20:40:14 +02003940int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003941{
Johan Hedbergca69b792011-11-11 18:10:00 +02003942 u8 mgmt_err = mgmt_status(status);
3943
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003944 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003945 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003946 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003947
3948 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003949 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003950 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003951
3952 return 0;
3953}
3954
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003955int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3956 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003957{
Johan Hedberg86742e12011-11-07 23:13:38 +02003958 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003959
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003960 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003961
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003962 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003963 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003964 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003965 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003966 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003967 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003968
Johan Hedberg744cf192011-11-08 20:40:14 +02003969 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003970}
Johan Hedbergf7520542011-01-20 12:34:39 +02003971
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003972int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3973{
3974 struct mgmt_ev_new_long_term_key ev;
3975
3976 memset(&ev, 0, sizeof(ev));
3977
3978 ev.store_hint = persistent;
3979 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003980 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003981 ev.key.authenticated = key->authenticated;
3982 ev.key.enc_size = key->enc_size;
3983 ev.key.ediv = key->ediv;
3984
3985 if (key->type == HCI_SMP_LTK)
3986 ev.key.master = 1;
3987
3988 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3989 memcpy(ev.key.val, key->val, sizeof(key->val));
3990
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003991 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3992 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003993}
3994
Johan Hedbergafc747a2012-01-15 18:11:07 +02003995int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003996 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3997 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003998{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003999 char buf[512];
4000 struct mgmt_ev_device_connected *ev = (void *) buf;
4001 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004002
Johan Hedbergb644ba32012-01-17 21:48:47 +02004003 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004004 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004005
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004006 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004007
Johan Hedbergb644ba32012-01-17 21:48:47 +02004008 if (name_len > 0)
4009 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004010 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004011
4012 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004013 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004014 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004015
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004016 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004017
4018 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004019 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004020}
4021
Johan Hedberg8962ee72011-01-20 12:40:27 +02004022static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4023{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004024 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004025 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004026 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004027
Johan Hedberg88c3df12012-02-09 14:27:38 +02004028 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4029 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004030
Johan Hedbergaee9b212012-02-18 15:07:59 +02004031 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004032 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004033
4034 *sk = cmd->sk;
4035 sock_hold(*sk);
4036
Johan Hedberga664b5b2011-02-19 12:06:02 -03004037 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004038}
4039
Johan Hedberg124f6e32012-02-09 13:50:12 +02004040static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004041{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004042 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004043 struct mgmt_cp_unpair_device *cp = cmd->param;
4044 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004045
4046 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004047 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4048 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004049
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004050 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4051
Johan Hedbergaee9b212012-02-18 15:07:59 +02004052 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004053
4054 mgmt_pending_remove(cmd);
4055}
4056
Johan Hedbergafc747a2012-01-15 18:11:07 +02004057int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004058 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004059{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004060 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004061 struct sock *sk = NULL;
4062 int err;
4063
Johan Hedberg744cf192011-11-08 20:40:14 +02004064 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004065
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004066 bacpy(&ev.addr.bdaddr, bdaddr);
4067 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4068 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004069
Johan Hedbergafc747a2012-01-15 18:11:07 +02004070 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004071 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004072
4073 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004074 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004075
Johan Hedberg124f6e32012-02-09 13:50:12 +02004076 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004077 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004078
Johan Hedberg8962ee72011-01-20 12:40:27 +02004079 return err;
4080}
4081
Johan Hedberg88c3df12012-02-09 14:27:38 +02004082int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004083 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004084{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004085 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004086 struct pending_cmd *cmd;
4087 int err;
4088
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004089 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4090 hdev);
4091
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004092 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004093 if (!cmd)
4094 return -ENOENT;
4095
Johan Hedberg88c3df12012-02-09 14:27:38 +02004096 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004097 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004098
Johan Hedberg88c3df12012-02-09 14:27:38 +02004099 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004100 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004101
Johan Hedberga664b5b2011-02-19 12:06:02 -03004102 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004103
4104 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004105}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004106
Johan Hedberg48264f02011-11-09 13:58:58 +02004107int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004108 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004109{
4110 struct mgmt_ev_connect_failed ev;
4111
Johan Hedberg4c659c32011-11-07 23:13:39 +02004112 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004113 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004114 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004115
Johan Hedberg744cf192011-11-08 20:40:14 +02004116 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004117}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004118
Johan Hedberg744cf192011-11-08 20:40:14 +02004119int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004120{
4121 struct mgmt_ev_pin_code_request ev;
4122
Johan Hedbergd8457692012-02-17 14:24:57 +02004123 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004124 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004125 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004126
Johan Hedberg744cf192011-11-08 20:40:14 +02004127 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004128 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004129}
4130
Johan Hedberg744cf192011-11-08 20:40:14 +02004131int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004132 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004133{
4134 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004135 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004136 int err;
4137
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004138 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004139 if (!cmd)
4140 return -ENOENT;
4141
Johan Hedbergd8457692012-02-17 14:24:57 +02004142 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004143 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004144
Johan Hedbergaee9b212012-02-18 15:07:59 +02004145 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004146 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004147
Johan Hedberga664b5b2011-02-19 12:06:02 -03004148 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004149
4150 return err;
4151}
4152
Johan Hedberg744cf192011-11-08 20:40:14 +02004153int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004154 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004155{
4156 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004157 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004158 int err;
4159
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004160 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004161 if (!cmd)
4162 return -ENOENT;
4163
Johan Hedbergd8457692012-02-17 14:24:57 +02004164 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004165 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004166
Johan Hedbergaee9b212012-02-18 15:07:59 +02004167 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004168 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004169
Johan Hedberga664b5b2011-02-19 12:06:02 -03004170 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004171
4172 return err;
4173}
Johan Hedberga5c29682011-02-19 12:05:57 -03004174
Johan Hedberg744cf192011-11-08 20:40:14 +02004175int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004176 u8 link_type, u8 addr_type, __le32 value,
4177 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004178{
4179 struct mgmt_ev_user_confirm_request ev;
4180
Johan Hedberg744cf192011-11-08 20:40:14 +02004181 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004182
Johan Hedberg272d90d2012-02-09 15:26:12 +02004183 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004184 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004185 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004186 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004187
Johan Hedberg744cf192011-11-08 20:40:14 +02004188 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004189 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004190}
4191
Johan Hedberg272d90d2012-02-09 15:26:12 +02004192int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004193 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004194{
4195 struct mgmt_ev_user_passkey_request ev;
4196
4197 BT_DBG("%s", hdev->name);
4198
Johan Hedberg272d90d2012-02-09 15:26:12 +02004199 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004200 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004201
4202 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004203 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004204}
4205
Brian Gix0df4c182011-11-16 13:53:13 -08004206static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004207 u8 link_type, u8 addr_type, u8 status,
4208 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004209{
4210 struct pending_cmd *cmd;
4211 struct mgmt_rp_user_confirm_reply rp;
4212 int err;
4213
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004214 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004215 if (!cmd)
4216 return -ENOENT;
4217
Johan Hedberg272d90d2012-02-09 15:26:12 +02004218 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004219 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004220 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004221 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004222
Johan Hedberga664b5b2011-02-19 12:06:02 -03004223 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004224
4225 return err;
4226}
4227
Johan Hedberg744cf192011-11-08 20:40:14 +02004228int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004229 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004230{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004231 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004232 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004233}
4234
Johan Hedberg272d90d2012-02-09 15:26:12 +02004235int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004236 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004237{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004238 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004239 status,
4240 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004241}
Johan Hedberg2a611692011-02-19 12:06:00 -03004242
Brian Gix604086b2011-11-23 08:28:33 -08004243int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004244 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004245{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004246 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004247 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004248}
4249
Johan Hedberg272d90d2012-02-09 15:26:12 +02004250int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004251 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004252{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004253 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004254 status,
4255 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004256}
4257
Johan Hedberg92a25252012-09-06 18:39:26 +03004258int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4259 u8 link_type, u8 addr_type, u32 passkey,
4260 u8 entered)
4261{
4262 struct mgmt_ev_passkey_notify ev;
4263
4264 BT_DBG("%s", hdev->name);
4265
4266 bacpy(&ev.addr.bdaddr, bdaddr);
4267 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4268 ev.passkey = __cpu_to_le32(passkey);
4269 ev.entered = entered;
4270
4271 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4272}
4273
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004274int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004275 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004276{
4277 struct mgmt_ev_auth_failed ev;
4278
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004279 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004280 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004281 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004282
Johan Hedberg744cf192011-11-08 20:40:14 +02004283 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004284}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004285
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004286int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4287{
4288 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004289 bool changed = false;
4290 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004291
4292 if (status) {
4293 u8 mgmt_err = mgmt_status(status);
4294 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004295 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004296 return 0;
4297 }
4298
Johan Hedberg47990ea2012-02-22 11:58:37 +02004299 if (test_bit(HCI_AUTH, &hdev->flags)) {
4300 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4301 changed = true;
4302 } else {
4303 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4304 changed = true;
4305 }
4306
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004307 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004308 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004309
Johan Hedberg47990ea2012-02-22 11:58:37 +02004310 if (changed)
4311 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004312
4313 if (match.sk)
4314 sock_put(match.sk);
4315
4316 return err;
4317}
4318
Johan Hedberg890ea892013-03-15 17:06:52 -05004319static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004320{
Johan Hedberg890ea892013-03-15 17:06:52 -05004321 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004322 struct hci_cp_write_eir cp;
4323
Johan Hedberg976eb202012-10-24 21:12:01 +03004324 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004325 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004326
Johan Hedbergc80da272012-02-22 15:38:48 +02004327 memset(hdev->eir, 0, sizeof(hdev->eir));
4328
Johan Hedbergcacaf522012-02-21 00:52:42 +02004329 memset(&cp, 0, sizeof(cp));
4330
Johan Hedberg890ea892013-03-15 17:06:52 -05004331 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004332}
4333
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004334int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004335{
4336 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004337 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004338 bool changed = false;
4339 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004340
4341 if (status) {
4342 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004343
4344 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004345 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004346 err = new_settings(hdev, NULL);
4347
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004348 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4349 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004350
4351 return err;
4352 }
4353
4354 if (enable) {
4355 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4356 changed = true;
4357 } else {
4358 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4359 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004360 }
4361
4362 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4363
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004364 if (changed)
4365 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004366
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004367 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004368 sock_put(match.sk);
4369
Johan Hedberg890ea892013-03-15 17:06:52 -05004370 hci_req_init(&req, hdev);
4371
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004372 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004373 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004374 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004375 clear_eir(&req);
4376
4377 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004378
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004379 return err;
4380}
4381
Johan Hedberg92da6092013-03-15 17:06:55 -05004382static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004383{
4384 struct cmd_lookup *match = data;
4385
Johan Hedberg90e70452012-02-23 23:09:40 +02004386 if (match->sk == NULL) {
4387 match->sk = cmd->sk;
4388 sock_hold(match->sk);
4389 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004390}
4391
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004392int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004393 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004394{
Johan Hedberg90e70452012-02-23 23:09:40 +02004395 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4396 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004397
Johan Hedberg92da6092013-03-15 17:06:55 -05004398 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4399 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4400 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004401
4402 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004403 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4404 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004405
4406 if (match.sk)
4407 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004408
4409 return err;
4410}
4411
Johan Hedberg744cf192011-11-08 20:40:14 +02004412int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004413{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004414 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004415 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004416
Johan Hedberg13928972013-03-15 17:07:00 -05004417 if (status)
4418 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004419
4420 memset(&ev, 0, sizeof(ev));
4421 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004422 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004423
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004424 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004425 if (!cmd) {
4426 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004427
Johan Hedberg13928972013-03-15 17:07:00 -05004428 /* If this is a HCI command related to powering on the
4429 * HCI dev don't send any mgmt signals.
4430 */
4431 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4432 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004433 }
4434
Johan Hedberg13928972013-03-15 17:07:00 -05004435 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4436 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004437}
Szymon Jancc35938b2011-03-22 13:12:21 +01004438
Johan Hedberg744cf192011-11-08 20:40:14 +02004439int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004440 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004441{
4442 struct pending_cmd *cmd;
4443 int err;
4444
Johan Hedberg744cf192011-11-08 20:40:14 +02004445 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004446
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004447 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004448 if (!cmd)
4449 return -ENOENT;
4450
4451 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004452 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4453 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004454 } else {
4455 struct mgmt_rp_read_local_oob_data rp;
4456
4457 memcpy(rp.hash, hash, sizeof(rp.hash));
4458 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4459
Johan Hedberg744cf192011-11-08 20:40:14 +02004460 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004461 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4462 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004463 }
4464
4465 mgmt_pending_remove(cmd);
4466
4467 return err;
4468}
Johan Hedberge17acd42011-03-30 23:57:16 +03004469
Johan Hedberg48264f02011-11-09 13:58:58 +02004470int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004471 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4472 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004473{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004474 char buf[512];
4475 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004476 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004477
Andre Guedes12602d02013-04-30 15:29:40 -03004478 if (!hci_discovery_active(hdev))
4479 return -EPERM;
4480
Johan Hedberg1dc06092012-01-15 21:01:23 +02004481 /* Leave 5 bytes for a potential CoD field */
4482 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004483 return -EINVAL;
4484
Johan Hedberg1dc06092012-01-15 21:01:23 +02004485 memset(buf, 0, sizeof(buf));
4486
Johan Hedberge319d2e2012-01-15 19:51:59 +02004487 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004488 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004489 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004490 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304491 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004492 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304493 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004494
Johan Hedberg1dc06092012-01-15 21:01:23 +02004495 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004496 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004497
Johan Hedberg1dc06092012-01-15 21:01:23 +02004498 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4499 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004500 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004501
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004502 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004503 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004504
Johan Hedberge319d2e2012-01-15 19:51:59 +02004505 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004506}
Johan Hedberga88a9652011-03-30 13:18:12 +03004507
Johan Hedbergb644ba32012-01-17 21:48:47 +02004508int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004509 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004510{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004511 struct mgmt_ev_device_found *ev;
4512 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4513 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004514
Johan Hedbergb644ba32012-01-17 21:48:47 +02004515 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004516
Johan Hedbergb644ba32012-01-17 21:48:47 +02004517 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004518
Johan Hedbergb644ba32012-01-17 21:48:47 +02004519 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004520 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004521 ev->rssi = rssi;
4522
4523 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004524 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004525
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004526 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004527
Johan Hedberg053c7e02012-02-04 00:06:00 +02004528 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004529 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004530}
Johan Hedberg314b2382011-04-27 10:29:57 -04004531
Johan Hedberg744cf192011-11-08 20:40:14 +02004532int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004533{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004534 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004535 struct pending_cmd *cmd;
4536
Andre Guedes343fb142011-11-22 17:14:19 -03004537 BT_DBG("%s discovering %u", hdev->name, discovering);
4538
Johan Hedberg164a6e72011-11-01 17:06:44 +02004539 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004540 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004541 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004542 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004543
4544 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004545 u8 type = hdev->discovery.type;
4546
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004547 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4548 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004549 mgmt_pending_remove(cmd);
4550 }
4551
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004552 memset(&ev, 0, sizeof(ev));
4553 ev.type = hdev->discovery.type;
4554 ev.discovering = discovering;
4555
4556 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004557}
Antti Julku5e762442011-08-25 16:48:02 +03004558
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004559int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004560{
4561 struct pending_cmd *cmd;
4562 struct mgmt_ev_device_blocked ev;
4563
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004564 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004565
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004566 bacpy(&ev.addr.bdaddr, bdaddr);
4567 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004568
Johan Hedberg744cf192011-11-08 20:40:14 +02004569 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004570 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004571}
4572
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004573int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004574{
4575 struct pending_cmd *cmd;
4576 struct mgmt_ev_device_unblocked ev;
4577
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004578 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004579
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004580 bacpy(&ev.addr.bdaddr, bdaddr);
4581 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004582
Johan Hedberg744cf192011-11-08 20:40:14 +02004583 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004584 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004585}