blob: ad3862949a2c489f700e2412612089afba13f6e7 [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 Hedberge70bb2e2012-02-13 16:59:33 +020078};
79
80static const u16 mgmt_events[] = {
81 MGMT_EV_CONTROLLER_ERROR,
82 MGMT_EV_INDEX_ADDED,
83 MGMT_EV_INDEX_REMOVED,
84 MGMT_EV_NEW_SETTINGS,
85 MGMT_EV_CLASS_OF_DEV_CHANGED,
86 MGMT_EV_LOCAL_NAME_CHANGED,
87 MGMT_EV_NEW_LINK_KEY,
88 MGMT_EV_NEW_LONG_TERM_KEY,
89 MGMT_EV_DEVICE_CONNECTED,
90 MGMT_EV_DEVICE_DISCONNECTED,
91 MGMT_EV_CONNECT_FAILED,
92 MGMT_EV_PIN_CODE_REQUEST,
93 MGMT_EV_USER_CONFIRM_REQUEST,
94 MGMT_EV_USER_PASSKEY_REQUEST,
95 MGMT_EV_AUTH_FAILED,
96 MGMT_EV_DEVICE_FOUND,
97 MGMT_EV_DISCOVERING,
98 MGMT_EV_DEVICE_BLOCKED,
99 MGMT_EV_DEVICE_UNBLOCKED,
100 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300101 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200102};
103
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800104#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200105
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200106#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
107 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
108
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200109struct pending_cmd {
110 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200111 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200112 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100113 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300115 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116};
117
Johan Hedbergca69b792011-11-11 18:10:00 +0200118/* HCI to MGMT error code conversion table */
119static u8 mgmt_status_table[] = {
120 MGMT_STATUS_SUCCESS,
121 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
122 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
123 MGMT_STATUS_FAILED, /* Hardware Failure */
124 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
125 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
126 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
127 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
128 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
129 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
130 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
131 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
132 MGMT_STATUS_BUSY, /* Command Disallowed */
133 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
134 MGMT_STATUS_REJECTED, /* Rejected Security */
135 MGMT_STATUS_REJECTED, /* Rejected Personal */
136 MGMT_STATUS_TIMEOUT, /* Host Timeout */
137 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
138 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
139 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
140 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
141 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
142 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
143 MGMT_STATUS_BUSY, /* Repeated Attempts */
144 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
145 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
146 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
147 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
148 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
149 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
150 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
151 MGMT_STATUS_FAILED, /* Unspecified Error */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
153 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
154 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
155 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
156 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
157 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
158 MGMT_STATUS_FAILED, /* Unit Link Key Used */
159 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
160 MGMT_STATUS_TIMEOUT, /* Instant Passed */
161 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
162 MGMT_STATUS_FAILED, /* Transaction Collision */
163 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
164 MGMT_STATUS_REJECTED, /* QoS Rejected */
165 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
166 MGMT_STATUS_REJECTED, /* Insufficient Security */
167 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
168 MGMT_STATUS_BUSY, /* Role Switch Pending */
169 MGMT_STATUS_FAILED, /* Slot Violation */
170 MGMT_STATUS_FAILED, /* Role Switch Failed */
171 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
172 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
173 MGMT_STATUS_BUSY, /* Host Busy Pairing */
174 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
175 MGMT_STATUS_BUSY, /* Controller Busy */
176 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
177 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
178 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
179 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
180 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
181};
182
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300183bool mgmt_valid_hdev(struct hci_dev *hdev)
184{
185 return hdev->dev_type == HCI_BREDR;
186}
187
Johan Hedbergca69b792011-11-11 18:10:00 +0200188static u8 mgmt_status(u8 hci_status)
189{
190 if (hci_status < ARRAY_SIZE(mgmt_status_table))
191 return mgmt_status_table[hci_status];
192
193 return MGMT_STATUS_FAILED;
194}
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200197{
198 struct sk_buff *skb;
199 struct mgmt_hdr *hdr;
200 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300201 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Szymon Janc34eb5252011-02-28 14:10:08 +0100203 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204
Andre Guedes790eff42012-06-07 19:05:46 -0300205 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200206 if (!skb)
207 return -ENOMEM;
208
209 hdr = (void *) skb_put(skb, sizeof(*hdr));
210
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530211 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100212 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200213 hdr->len = cpu_to_le16(sizeof(*ev));
214
215 ev = (void *) skb_put(skb, sizeof(*ev));
216 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200217 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200218
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300219 err = sock_queue_rcv_skb(sk, skb);
220 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221 kfree_skb(skb);
222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200224}
225
Johan Hedbergaee9b212012-02-18 15:07:59 +0200226static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300227 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200228{
229 struct sk_buff *skb;
230 struct mgmt_hdr *hdr;
231 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300232 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200233
234 BT_DBG("sock %p", sk);
235
Andre Guedes790eff42012-06-07 19:05:46 -0300236 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200237 if (!skb)
238 return -ENOMEM;
239
240 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200241
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530242 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100243 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200247 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200248 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100249
250 if (rp)
251 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200252
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300253 err = sock_queue_rcv_skb(sk, skb);
254 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200255 kfree_skb(skb);
256
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100257 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200258}
259
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300260static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
261 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200262{
263 struct mgmt_rp_read_version rp;
264
265 BT_DBG("sock %p", sk);
266
267 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200268 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200269
Johan Hedbergaee9b212012-02-18 15:07:59 +0200270 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200272}
273
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
275 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200276{
277 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200278 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
279 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200280 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200281 size_t rp_size;
282 int i, err;
283
284 BT_DBG("sock %p", sk);
285
286 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
287
288 rp = kmalloc(rp_size, GFP_KERNEL);
289 if (!rp)
290 return -ENOMEM;
291
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200292 rp->num_commands = __constant_cpu_to_le16(num_commands);
293 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200294
295 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
296 put_unaligned_le16(mgmt_commands[i], opcode);
297
298 for (i = 0; i < num_events; i++, opcode++)
299 put_unaligned_le16(mgmt_events[i], opcode);
300
Johan Hedbergaee9b212012-02-18 15:07:59 +0200301 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300302 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200303 kfree(rp);
304
305 return err;
306}
307
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300308static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
309 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200312 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200313 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200314 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300315 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316
317 BT_DBG("sock %p", sk);
318
319 read_lock(&hci_dev_list_lock);
320
321 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300322 list_for_each_entry(d, &hci_dev_list, list) {
323 if (!mgmt_valid_hdev(d))
324 continue;
325
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200326 count++;
327 }
328
Johan Hedberga38528f2011-01-22 06:46:43 +0200329 rp_len = sizeof(*rp) + (2 * count);
330 rp = kmalloc(rp_len, GFP_ATOMIC);
331 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100332 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200333 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100334 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200335
Johan Hedberg476e44c2012-10-19 20:10:46 +0300336 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200337 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200338 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200339 continue;
340
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700341 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
342 continue;
343
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300344 if (!mgmt_valid_hdev(d))
345 continue;
346
Johan Hedberg476e44c2012-10-19 20:10:46 +0300347 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 BT_DBG("Added hci%u", d->id);
349 }
350
Johan Hedberg476e44c2012-10-19 20:10:46 +0300351 rp->num_controllers = cpu_to_le16(count);
352 rp_len = sizeof(*rp) + (2 * count);
353
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354 read_unlock(&hci_dev_list_lock);
355
Johan Hedbergaee9b212012-02-18 15:07:59 +0200356 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300357 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358
Johan Hedberga38528f2011-01-22 06:46:43 +0200359 kfree(rp);
360
361 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200362}
363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200365{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200367
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200370
Andre Guedes9a1a1992012-07-24 15:03:48 -0300371 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200373
Andre Guedesed3fa312012-07-24 15:03:46 -0300374 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300375 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500376 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
377 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300378 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 settings |= MGMT_SETTING_BREDR;
380 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100381 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700382 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300384 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200385 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300386 settings |= MGMT_SETTING_ADVERTISING;
387 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389 return settings;
390}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392static u32 get_current_settings(struct hci_dev *hdev)
393{
394 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200395
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200396 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100397 settings |= MGMT_SETTING_POWERED;
398
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200399 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 settings |= MGMT_SETTING_CONNECTABLE;
401
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500402 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
403 settings |= MGMT_SETTING_FAST_CONNECTABLE;
404
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200405 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_DISCOVERABLE;
407
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200408 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_PAIRABLE;
410
Andre Guedesed3fa312012-07-24 15:03:46 -0300411 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_BREDR;
413
Johan Hedberg06199cf2012-02-22 16:37:11 +0200414 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg47990ea2012-02-22 11:58:37 +0200417 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200420 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200422
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200423 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
424 settings |= MGMT_SETTING_HS;
425
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300426 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
427 settings |= MGMT_SETTING_ADVERTISING;
428
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200429 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200430}
431
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300432#define PNP_INFO_SVCLASS_ID 0x1200
433
Johan Hedberg213202e2013-01-27 00:31:33 +0200434static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
435{
436 u8 *ptr = data, *uuids_start = NULL;
437 struct bt_uuid *uuid;
438
439 if (len < 4)
440 return ptr;
441
442 list_for_each_entry(uuid, &hdev->uuids, list) {
443 u16 uuid16;
444
445 if (uuid->size != 16)
446 continue;
447
448 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
449 if (uuid16 < 0x1100)
450 continue;
451
452 if (uuid16 == PNP_INFO_SVCLASS_ID)
453 continue;
454
455 if (!uuids_start) {
456 uuids_start = ptr;
457 uuids_start[0] = 1;
458 uuids_start[1] = EIR_UUID16_ALL;
459 ptr += 2;
460 }
461
462 /* Stop if not enough space to put next UUID */
463 if ((ptr - data) + sizeof(u16) > len) {
464 uuids_start[1] = EIR_UUID16_SOME;
465 break;
466 }
467
468 *ptr++ = (uuid16 & 0x00ff);
469 *ptr++ = (uuid16 & 0xff00) >> 8;
470 uuids_start[0] += sizeof(uuid16);
471 }
472
473 return ptr;
474}
475
Johan Hedbergcdf19632013-01-27 00:31:34 +0200476static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
477{
478 u8 *ptr = data, *uuids_start = NULL;
479 struct bt_uuid *uuid;
480
481 if (len < 6)
482 return ptr;
483
484 list_for_each_entry(uuid, &hdev->uuids, list) {
485 if (uuid->size != 32)
486 continue;
487
488 if (!uuids_start) {
489 uuids_start = ptr;
490 uuids_start[0] = 1;
491 uuids_start[1] = EIR_UUID32_ALL;
492 ptr += 2;
493 }
494
495 /* Stop if not enough space to put next UUID */
496 if ((ptr - data) + sizeof(u32) > len) {
497 uuids_start[1] = EIR_UUID32_SOME;
498 break;
499 }
500
501 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
502 ptr += sizeof(u32);
503 uuids_start[0] += sizeof(u32);
504 }
505
506 return ptr;
507}
508
Johan Hedbergc00d5752013-01-27 00:31:35 +0200509static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
510{
511 u8 *ptr = data, *uuids_start = NULL;
512 struct bt_uuid *uuid;
513
514 if (len < 18)
515 return ptr;
516
517 list_for_each_entry(uuid, &hdev->uuids, list) {
518 if (uuid->size != 128)
519 continue;
520
521 if (!uuids_start) {
522 uuids_start = ptr;
523 uuids_start[0] = 1;
524 uuids_start[1] = EIR_UUID128_ALL;
525 ptr += 2;
526 }
527
528 /* Stop if not enough space to put next UUID */
529 if ((ptr - data) + 16 > len) {
530 uuids_start[1] = EIR_UUID128_SOME;
531 break;
532 }
533
534 memcpy(ptr, uuid->uuid, 16);
535 ptr += 16;
536 uuids_start[0] += 16;
537 }
538
539 return ptr;
540}
541
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542static void create_eir(struct hci_dev *hdev, u8 *data)
543{
544 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 size_t name_len;
546
547 name_len = strlen(hdev->dev_name);
548
549 if (name_len > 0) {
550 /* EIR Data type */
551 if (name_len > 48) {
552 name_len = 48;
553 ptr[1] = EIR_NAME_SHORT;
554 } else
555 ptr[1] = EIR_NAME_COMPLETE;
556
557 /* EIR Data length */
558 ptr[0] = name_len + 1;
559
560 memcpy(ptr + 2, hdev->dev_name, name_len);
561
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300562 ptr += (name_len + 2);
563 }
564
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100565 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700566 ptr[0] = 2;
567 ptr[1] = EIR_TX_POWER;
568 ptr[2] = (u8) hdev->inq_tx_power;
569
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700570 ptr += 3;
571 }
572
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700573 if (hdev->devid_source > 0) {
574 ptr[0] = 9;
575 ptr[1] = EIR_DEVICE_ID;
576
577 put_unaligned_le16(hdev->devid_source, ptr + 2);
578 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
579 put_unaligned_le16(hdev->devid_product, ptr + 6);
580 put_unaligned_le16(hdev->devid_version, ptr + 8);
581
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700582 ptr += 10;
583 }
584
Johan Hedberg213202e2013-01-27 00:31:33 +0200585 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200586 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200587 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300588}
589
Johan Hedberg890ea892013-03-15 17:06:52 -0500590static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300591{
Johan Hedberg890ea892013-03-15 17:06:52 -0500592 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300593 struct hci_cp_write_eir cp;
594
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200595 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500596 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200597
Johan Hedberg976eb202012-10-24 21:12:01 +0300598 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500599 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300600
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200601 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500602 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300603
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200604 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500605 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300606
607 memset(&cp, 0, sizeof(cp));
608
609 create_eir(hdev, cp.data);
610
611 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500612 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300613
614 memcpy(hdev->eir, cp.data, sizeof(cp.data));
615
Johan Hedberg890ea892013-03-15 17:06:52 -0500616 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300617}
618
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200619static u8 get_service_classes(struct hci_dev *hdev)
620{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300621 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200622 u8 val = 0;
623
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300624 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200625 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200626
627 return val;
628}
629
Johan Hedberg890ea892013-03-15 17:06:52 -0500630static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200631{
Johan Hedberg890ea892013-03-15 17:06:52 -0500632 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200633 u8 cod[3];
634
635 BT_DBG("%s", hdev->name);
636
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200637 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500638 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200639
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200640 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500641 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200642
643 cod[0] = hdev->minor_class;
644 cod[1] = hdev->major_class;
645 cod[2] = get_service_classes(hdev);
646
647 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500648 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200649
Johan Hedberg890ea892013-03-15 17:06:52 -0500650 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200651}
652
Johan Hedberg7d785252011-12-15 00:47:39 +0200653static void service_cache_off(struct work_struct *work)
654{
655 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300656 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500657 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200658
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200659 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200660 return;
661
Johan Hedberg890ea892013-03-15 17:06:52 -0500662 hci_req_init(&req, hdev);
663
Johan Hedberg7d785252011-12-15 00:47:39 +0200664 hci_dev_lock(hdev);
665
Johan Hedberg890ea892013-03-15 17:06:52 -0500666 update_eir(&req);
667 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200668
669 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500670
671 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200672}
673
Johan Hedberg6a919082012-02-28 06:17:26 +0200674static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200675{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200676 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200677 return;
678
Johan Hedberg4f87da82012-03-02 19:55:56 +0200679 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200680
Johan Hedberg4f87da82012-03-02 19:55:56 +0200681 /* Non-mgmt controlled devices get this bit set
682 * implicitly so that pairing works for them, however
683 * for mgmt we require user-space to explicitly enable
684 * it
685 */
686 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200687}
688
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200689static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300690 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200691{
692 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200693
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200694 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300696 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200697
Johan Hedberg03811012010-12-08 00:21:06 +0200698 memset(&rp, 0, sizeof(rp));
699
Johan Hedberg03811012010-12-08 00:21:06 +0200700 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200701
702 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200703 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200704
705 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
706 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
707
708 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200709
710 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200711 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200712
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300713 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200714
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200715 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300716 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200717}
718
719static void mgmt_pending_free(struct pending_cmd *cmd)
720{
721 sock_put(cmd->sk);
722 kfree(cmd->param);
723 kfree(cmd);
724}
725
726static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300727 struct hci_dev *hdev, void *data,
728 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200729{
730 struct pending_cmd *cmd;
731
Andre Guedes12b94562012-06-07 19:05:45 -0300732 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200733 if (!cmd)
734 return NULL;
735
736 cmd->opcode = opcode;
737 cmd->index = hdev->id;
738
Andre Guedes12b94562012-06-07 19:05:45 -0300739 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200740 if (!cmd->param) {
741 kfree(cmd);
742 return NULL;
743 }
744
745 if (data)
746 memcpy(cmd->param, data, len);
747
748 cmd->sk = sk;
749 sock_hold(sk);
750
751 list_add(&cmd->list, &hdev->mgmt_pending);
752
753 return cmd;
754}
755
756static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300757 void (*cb)(struct pending_cmd *cmd,
758 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300759 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200760{
Andre Guedesa3d09352013-02-01 11:21:30 -0300761 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200762
Andre Guedesa3d09352013-02-01 11:21:30 -0300763 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200764 if (opcode > 0 && cmd->opcode != opcode)
765 continue;
766
767 cb(cmd, data);
768 }
769}
770
771static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
772{
773 struct pending_cmd *cmd;
774
775 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
776 if (cmd->opcode == opcode)
777 return cmd;
778 }
779
780 return NULL;
781}
782
783static void mgmt_pending_remove(struct pending_cmd *cmd)
784{
785 list_del(&cmd->list);
786 mgmt_pending_free(cmd);
787}
788
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200789static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200790{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200792
Johan Hedbergaee9b212012-02-18 15:07:59 +0200793 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300794 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200795}
796
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200797static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300798 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200799{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300800 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200801 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200802 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200803
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200804 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedberga7e80f22013-01-09 16:05:19 +0200806 if (cp->val != 0x00 && cp->val != 0x01)
807 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
808 MGMT_STATUS_INVALID_PARAMS);
809
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300810 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200811
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300812 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
813 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
814 MGMT_STATUS_BUSY);
815 goto failed;
816 }
817
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100818 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
819 cancel_delayed_work(&hdev->power_off);
820
821 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200822 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
823 data, len);
824 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100825 goto failed;
826 }
827 }
828
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200829 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200830 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200831 goto failed;
832 }
833
Johan Hedberg03811012010-12-08 00:21:06 +0200834 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
835 if (!cmd) {
836 err = -ENOMEM;
837 goto failed;
838 }
839
840 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200841 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200842 else
Johan Hedberg19202572013-01-14 22:33:51 +0200843 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200844
845 err = 0;
846
847failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300848 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200849 return err;
850}
851
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300852static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
853 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200854{
855 struct sk_buff *skb;
856 struct mgmt_hdr *hdr;
857
Andre Guedes790eff42012-06-07 19:05:46 -0300858 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200859 if (!skb)
860 return -ENOMEM;
861
862 hdr = (void *) skb_put(skb, sizeof(*hdr));
863 hdr->opcode = cpu_to_le16(event);
864 if (hdev)
865 hdr->index = cpu_to_le16(hdev->id);
866 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530867 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200868 hdr->len = cpu_to_le16(data_len);
869
870 if (data)
871 memcpy(skb_put(skb, data_len), data, data_len);
872
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100873 /* Time stamp */
874 __net_timestamp(skb);
875
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200876 hci_send_to_control(skb, skip_sk);
877 kfree_skb(skb);
878
879 return 0;
880}
881
882static int new_settings(struct hci_dev *hdev, struct sock *skip)
883{
884 __le32 ev;
885
886 ev = cpu_to_le32(get_current_settings(hdev));
887
888 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
889}
890
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300891struct cmd_lookup {
892 struct sock *sk;
893 struct hci_dev *hdev;
894 u8 mgmt_status;
895};
896
897static void settings_rsp(struct pending_cmd *cmd, void *data)
898{
899 struct cmd_lookup *match = data;
900
901 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
902
903 list_del(&cmd->list);
904
905 if (match->sk == NULL) {
906 match->sk = cmd->sk;
907 sock_hold(match->sk);
908 }
909
910 mgmt_pending_free(cmd);
911}
912
913static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
914{
915 u8 *status = data;
916
917 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
918 mgmt_pending_remove(cmd);
919}
920
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200921static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300922 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200923{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300924 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200925 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200926 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200927 u8 scan;
928 int err;
929
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200930 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200931
Johan Hedberg33c525c2012-10-24 21:11:58 +0300932 if (!lmp_bredr_capable(hdev))
933 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
934 MGMT_STATUS_NOT_SUPPORTED);
935
Johan Hedberga7e80f22013-01-09 16:05:19 +0200936 if (cp->val != 0x00 && cp->val != 0x01)
937 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
938 MGMT_STATUS_INVALID_PARAMS);
939
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700940 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100941 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200942 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300943 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200944
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300945 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200946
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200947 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200948 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300949 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200950 goto failed;
951 }
952
953 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300954 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200955 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300956 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200957 goto failed;
958 }
959
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200960 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200961 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300962 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200963 goto failed;
964 }
965
966 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200967 bool changed = false;
968
969 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
970 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
971 changed = true;
972 }
973
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200974 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200975 if (err < 0)
976 goto failed;
977
978 if (changed)
979 err = new_settings(hdev, sk);
980
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200981 goto failed;
982 }
983
984 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100985 if (hdev->discov_timeout > 0) {
986 cancel_delayed_work(&hdev->discov_off);
987 hdev->discov_timeout = 0;
988 }
989
990 if (cp->val && timeout > 0) {
991 hdev->discov_timeout = timeout;
992 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
993 msecs_to_jiffies(hdev->discov_timeout * 1000));
994 }
995
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200996 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200997 goto failed;
998 }
999
1000 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1001 if (!cmd) {
1002 err = -ENOMEM;
1003 goto failed;
1004 }
1005
1006 scan = SCAN_PAGE;
1007
1008 if (cp->val)
1009 scan |= SCAN_INQUIRY;
1010 else
1011 cancel_delayed_work(&hdev->discov_off);
1012
1013 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1014 if (err < 0)
1015 mgmt_pending_remove(cmd);
1016
Johan Hedberg03811012010-12-08 00:21:06 +02001017 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001018 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001019
1020failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001021 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001022 return err;
1023}
1024
Johan Hedberg406d7802013-03-15 17:07:09 -05001025static void write_fast_connectable(struct hci_request *req, bool enable)
1026{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001027 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001028 struct hci_cp_write_page_scan_activity acp;
1029 u8 type;
1030
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001031 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1032 return;
1033
Johan Hedberg406d7802013-03-15 17:07:09 -05001034 if (enable) {
1035 type = PAGE_SCAN_TYPE_INTERLACED;
1036
1037 /* 160 msec page scan interval */
1038 acp.interval = __constant_cpu_to_le16(0x0100);
1039 } else {
1040 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1041
1042 /* default 1.28 sec page scan */
1043 acp.interval = __constant_cpu_to_le16(0x0800);
1044 }
1045
1046 acp.window = __constant_cpu_to_le16(0x0012);
1047
Johan Hedbergbd98b992013-03-15 17:07:13 -05001048 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1049 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1050 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1051 sizeof(acp), &acp);
1052
1053 if (hdev->page_scan_type != type)
1054 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001055}
1056
Johan Hedberg2b76f452013-03-15 17:07:04 -05001057static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1058{
1059 struct pending_cmd *cmd;
1060
1061 BT_DBG("status 0x%02x", status);
1062
1063 hci_dev_lock(hdev);
1064
1065 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1066 if (!cmd)
1067 goto unlock;
1068
1069 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1070
1071 mgmt_pending_remove(cmd);
1072
1073unlock:
1074 hci_dev_unlock(hdev);
1075}
1076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001077static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001078 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001079{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001080 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001081 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001082 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001083 u8 scan;
1084 int err;
1085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001086 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001087
Johan Hedberg33c525c2012-10-24 21:11:58 +03001088 if (!lmp_bredr_capable(hdev))
1089 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1090 MGMT_STATUS_NOT_SUPPORTED);
1091
Johan Hedberga7e80f22013-01-09 16:05:19 +02001092 if (cp->val != 0x00 && cp->val != 0x01)
1093 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1094 MGMT_STATUS_INVALID_PARAMS);
1095
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001096 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001097
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001098 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001099 bool changed = false;
1100
1101 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1102 changed = true;
1103
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001104 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001105 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001106 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001107 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1108 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1109 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001110
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001111 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001112 if (err < 0)
1113 goto failed;
1114
1115 if (changed)
1116 err = new_settings(hdev, sk);
1117
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001118 goto failed;
1119 }
1120
1121 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001122 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001123 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001124 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001125 goto failed;
1126 }
1127
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001128 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001129 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001130 goto failed;
1131 }
1132
1133 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1134 if (!cmd) {
1135 err = -ENOMEM;
1136 goto failed;
1137 }
1138
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001139 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001140 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001141 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001142 scan = 0;
1143
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001144 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001145 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001146 cancel_delayed_work(&hdev->discov_off);
1147 }
1148
Johan Hedberg2b76f452013-03-15 17:07:04 -05001149 hci_req_init(&req, hdev);
1150
1151 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1152
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001153 /* If we're going from non-connectable to connectable or
1154 * vice-versa when fast connectable is enabled ensure that fast
1155 * connectable gets disabled. write_fast_connectable won't do
1156 * anything if the page scan parameters are already what they
1157 * should be.
1158 */
1159 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001160 write_fast_connectable(&req, false);
1161
Johan Hedberg2b76f452013-03-15 17:07:04 -05001162 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001163 if (err < 0)
1164 mgmt_pending_remove(cmd);
1165
1166failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001167 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001168 return err;
1169}
1170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001171static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001172 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001173{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001174 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001175 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001177 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001178
Johan Hedberga7e80f22013-01-09 16:05:19 +02001179 if (cp->val != 0x00 && cp->val != 0x01)
1180 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1181 MGMT_STATUS_INVALID_PARAMS);
1182
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001183 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001184
1185 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001186 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001188 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001189
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001190 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001191 if (err < 0)
1192 goto failed;
1193
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001194 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001195
1196failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001197 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001198 return err;
1199}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001200
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001201static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1202 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001203{
1204 struct mgmt_mode *cp = data;
1205 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001206 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001207 int err;
1208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001209 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001210
Johan Hedberg33c525c2012-10-24 21:11:58 +03001211 if (!lmp_bredr_capable(hdev))
1212 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1213 MGMT_STATUS_NOT_SUPPORTED);
1214
Johan Hedberga7e80f22013-01-09 16:05:19 +02001215 if (cp->val != 0x00 && cp->val != 0x01)
1216 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1217 MGMT_STATUS_INVALID_PARAMS);
1218
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001219 hci_dev_lock(hdev);
1220
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001221 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001222 bool changed = false;
1223
1224 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001225 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001226 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1227 changed = true;
1228 }
1229
1230 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1231 if (err < 0)
1232 goto failed;
1233
1234 if (changed)
1235 err = new_settings(hdev, sk);
1236
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001237 goto failed;
1238 }
1239
1240 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001241 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001242 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001243 goto failed;
1244 }
1245
1246 val = !!cp->val;
1247
1248 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1249 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1250 goto failed;
1251 }
1252
1253 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1254 if (!cmd) {
1255 err = -ENOMEM;
1256 goto failed;
1257 }
1258
1259 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1260 if (err < 0) {
1261 mgmt_pending_remove(cmd);
1262 goto failed;
1263 }
1264
1265failed:
1266 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001267 return err;
1268}
1269
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001270static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001271{
1272 struct mgmt_mode *cp = data;
1273 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001274 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001275 int err;
1276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001278
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001279 if (!lmp_ssp_capable(hdev))
1280 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1281 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001282
Johan Hedberga7e80f22013-01-09 16:05:19 +02001283 if (cp->val != 0x00 && cp->val != 0x01)
1284 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1285 MGMT_STATUS_INVALID_PARAMS);
1286
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001287 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001288
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001289 val = !!cp->val;
1290
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001291 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001292 bool changed = false;
1293
1294 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1295 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1296 changed = true;
1297 }
1298
1299 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1300 if (err < 0)
1301 goto failed;
1302
1303 if (changed)
1304 err = new_settings(hdev, sk);
1305
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001306 goto failed;
1307 }
1308
1309 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001310 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1311 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001312 goto failed;
1313 }
1314
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001315 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1316 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1317 goto failed;
1318 }
1319
1320 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1321 if (!cmd) {
1322 err = -ENOMEM;
1323 goto failed;
1324 }
1325
1326 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1327 if (err < 0) {
1328 mgmt_pending_remove(cmd);
1329 goto failed;
1330 }
1331
1332failed:
1333 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001334 return err;
1335}
1336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001337static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001338{
1339 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001340 bool changed;
1341 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001342
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001343 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001344
Marcel Holtmann848566b2013-10-01 22:59:22 -07001345 if (!lmp_bredr_capable(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001346 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001347 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001348
Johan Hedberga7e80f22013-01-09 16:05:19 +02001349 if (cp->val != 0x00 && cp->val != 0x01)
1350 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1351 MGMT_STATUS_INVALID_PARAMS);
1352
Marcel Holtmannee392692013-10-01 22:59:23 -07001353 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001354
Marcel Holtmannee392692013-10-01 22:59:23 -07001355 if (cp->val)
1356 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1357 else
1358 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1359
1360 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1361 if (err < 0)
1362 goto unlock;
1363
1364 if (changed)
1365 err = new_settings(hdev, sk);
1366
1367unlock:
1368 hci_dev_unlock(hdev);
1369 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001370}
1371
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001372static void le_enable_complete(struct hci_dev *hdev, u8 status)
1373{
1374 struct cmd_lookup match = { NULL, hdev };
1375
1376 if (status) {
1377 u8 mgmt_err = mgmt_status(status);
1378
1379 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1380 &mgmt_err);
1381 return;
1382 }
1383
1384 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1385
1386 new_settings(hdev, match.sk);
1387
1388 if (match.sk)
1389 sock_put(match.sk);
1390}
1391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001393{
1394 struct mgmt_mode *cp = data;
1395 struct hci_cp_write_le_host_supported hci_cp;
1396 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001397 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001398 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001399 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001401 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001402
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001403 if (!lmp_le_capable(hdev))
1404 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1405 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001406
Johan Hedberga7e80f22013-01-09 16:05:19 +02001407 if (cp->val != 0x00 && cp->val != 0x01)
1408 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1409 MGMT_STATUS_INVALID_PARAMS);
1410
Johan Hedbergc73eee92013-04-19 18:35:21 +03001411 /* LE-only devices do not allow toggling LE on/off */
1412 if (!lmp_bredr_capable(hdev))
1413 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1414 MGMT_STATUS_REJECTED);
1415
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001416 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001417
1418 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001419 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001420
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001421 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001422 bool changed = false;
1423
1424 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1425 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1426 changed = true;
1427 }
1428
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001429 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1430 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1431 changed = true;
1432 }
1433
Johan Hedberg06199cf2012-02-22 16:37:11 +02001434 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1435 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001436 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001437
1438 if (changed)
1439 err = new_settings(hdev, sk);
1440
Johan Hedberg1de028c2012-02-29 19:55:35 -08001441 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001442 }
1443
Johan Hedberg4375f102013-09-25 13:26:10 +03001444 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1445 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001446 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001447 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001448 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001449 }
1450
1451 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1452 if (!cmd) {
1453 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001454 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001455 }
1456
1457 memset(&hci_cp, 0, sizeof(hci_cp));
1458
1459 if (val) {
1460 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001461 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001462 }
1463
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001464 hci_req_init(&req, hdev);
1465
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001466 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1467 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1468
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001469 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1470 &hci_cp);
1471
1472 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301473 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001474 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001475
Johan Hedberg1de028c2012-02-29 19:55:35 -08001476unlock:
1477 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001478 return err;
1479}
1480
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001481/* This is a helper function to test for pending mgmt commands that can
1482 * cause CoD or EIR HCI commands. We can only allow one such pending
1483 * mgmt command at a time since otherwise we cannot easily track what
1484 * the current values are, will be, and based on that calculate if a new
1485 * HCI command needs to be sent and if yes with what value.
1486 */
1487static bool pending_eir_or_class(struct hci_dev *hdev)
1488{
1489 struct pending_cmd *cmd;
1490
1491 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1492 switch (cmd->opcode) {
1493 case MGMT_OP_ADD_UUID:
1494 case MGMT_OP_REMOVE_UUID:
1495 case MGMT_OP_SET_DEV_CLASS:
1496 case MGMT_OP_SET_POWERED:
1497 return true;
1498 }
1499 }
1500
1501 return false;
1502}
1503
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001504static const u8 bluetooth_base_uuid[] = {
1505 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1506 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1507};
1508
1509static u8 get_uuid_size(const u8 *uuid)
1510{
1511 u32 val;
1512
1513 if (memcmp(uuid, bluetooth_base_uuid, 12))
1514 return 128;
1515
1516 val = get_unaligned_le32(&uuid[12]);
1517 if (val > 0xffff)
1518 return 32;
1519
1520 return 16;
1521}
1522
Johan Hedberg92da6092013-03-15 17:06:55 -05001523static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1524{
1525 struct pending_cmd *cmd;
1526
1527 hci_dev_lock(hdev);
1528
1529 cmd = mgmt_pending_find(mgmt_op, hdev);
1530 if (!cmd)
1531 goto unlock;
1532
1533 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1534 hdev->dev_class, 3);
1535
1536 mgmt_pending_remove(cmd);
1537
1538unlock:
1539 hci_dev_unlock(hdev);
1540}
1541
1542static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1543{
1544 BT_DBG("status 0x%02x", status);
1545
1546 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1547}
1548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001550{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001551 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001552 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001553 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001554 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001555 int err;
1556
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001557 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001559 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001560
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001561 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001562 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001563 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001564 goto failed;
1565 }
1566
Andre Guedes92c4c202012-06-07 19:05:44 -03001567 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001568 if (!uuid) {
1569 err = -ENOMEM;
1570 goto failed;
1571 }
1572
1573 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001574 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001575 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001576
Johan Hedbergde66aa62013-01-27 00:31:27 +02001577 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001578
Johan Hedberg890ea892013-03-15 17:06:52 -05001579 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001580
Johan Hedberg890ea892013-03-15 17:06:52 -05001581 update_class(&req);
1582 update_eir(&req);
1583
Johan Hedberg92da6092013-03-15 17:06:55 -05001584 err = hci_req_run(&req, add_uuid_complete);
1585 if (err < 0) {
1586 if (err != -ENODATA)
1587 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001589 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001590 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001591 goto failed;
1592 }
1593
1594 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001595 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001596 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001597 goto failed;
1598 }
1599
1600 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001601
1602failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001603 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001604 return err;
1605}
1606
Johan Hedberg24b78d02012-02-23 23:24:30 +02001607static bool enable_service_cache(struct hci_dev *hdev)
1608{
1609 if (!hdev_is_powered(hdev))
1610 return false;
1611
1612 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001613 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1614 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001615 return true;
1616 }
1617
1618 return false;
1619}
1620
Johan Hedberg92da6092013-03-15 17:06:55 -05001621static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1622{
1623 BT_DBG("status 0x%02x", status);
1624
1625 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1626}
1627
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001628static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001629 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001631 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001632 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001633 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001634 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 -05001635 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001636 int err, found;
1637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001638 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001640 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001641
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001642 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001644 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001645 goto unlock;
1646 }
1647
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001648 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1649 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001650
Johan Hedberg24b78d02012-02-23 23:24:30 +02001651 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001652 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001653 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001654 goto unlock;
1655 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001656
Johan Hedberg9246a862012-02-23 21:33:16 +02001657 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001658 }
1659
1660 found = 0;
1661
Johan Hedberg056341c2013-01-27 00:31:30 +02001662 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001663 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1664 continue;
1665
1666 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001667 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001668 found++;
1669 }
1670
1671 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001672 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001673 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001674 goto unlock;
1675 }
1676
Johan Hedberg9246a862012-02-23 21:33:16 +02001677update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001678 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001679
Johan Hedberg890ea892013-03-15 17:06:52 -05001680 update_class(&req);
1681 update_eir(&req);
1682
Johan Hedberg92da6092013-03-15 17:06:55 -05001683 err = hci_req_run(&req, remove_uuid_complete);
1684 if (err < 0) {
1685 if (err != -ENODATA)
1686 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001688 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001689 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001690 goto unlock;
1691 }
1692
1693 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001694 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001695 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001696 goto unlock;
1697 }
1698
1699 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001700
1701unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001702 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001703 return err;
1704}
1705
Johan Hedberg92da6092013-03-15 17:06:55 -05001706static void set_class_complete(struct hci_dev *hdev, u8 status)
1707{
1708 BT_DBG("status 0x%02x", status);
1709
1710 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1711}
1712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001713static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001715{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001716 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001717 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001718 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001719 int err;
1720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001721 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001722
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001723 if (!lmp_bredr_capable(hdev))
1724 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1725 MGMT_STATUS_NOT_SUPPORTED);
1726
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001727 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001728
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001729 if (pending_eir_or_class(hdev)) {
1730 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1731 MGMT_STATUS_BUSY);
1732 goto unlock;
1733 }
1734
1735 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1736 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1737 MGMT_STATUS_INVALID_PARAMS);
1738 goto unlock;
1739 }
1740
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001741 hdev->major_class = cp->major;
1742 hdev->minor_class = cp->minor;
1743
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001744 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001745 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001746 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001747 goto unlock;
1748 }
1749
Johan Hedberg890ea892013-03-15 17:06:52 -05001750 hci_req_init(&req, hdev);
1751
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001752 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001753 hci_dev_unlock(hdev);
1754 cancel_delayed_work_sync(&hdev->service_cache);
1755 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001756 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001757 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001758
Johan Hedberg890ea892013-03-15 17:06:52 -05001759 update_class(&req);
1760
Johan Hedberg92da6092013-03-15 17:06:55 -05001761 err = hci_req_run(&req, set_class_complete);
1762 if (err < 0) {
1763 if (err != -ENODATA)
1764 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001765
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001766 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001767 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001768 goto unlock;
1769 }
1770
1771 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001772 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001773 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001774 goto unlock;
1775 }
1776
1777 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001778
Johan Hedbergb5235a62012-02-21 14:32:24 +02001779unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001780 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001781 return err;
1782}
1783
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001784static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001785 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001786{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001787 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001788 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001789 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001790
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001791 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001792
Johan Hedberg86742e12011-11-07 23:13:38 +02001793 expected_len = sizeof(*cp) + key_count *
1794 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001795 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001796 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001797 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001798 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001799 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001800 }
1801
Johan Hedberg4ae14302013-01-20 14:27:13 +02001802 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1803 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1804 MGMT_STATUS_INVALID_PARAMS);
1805
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001806 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001807 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001808
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001809 for (i = 0; i < key_count; i++) {
1810 struct mgmt_link_key_info *key = &cp->keys[i];
1811
1812 if (key->addr.type != BDADDR_BREDR)
1813 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1814 MGMT_STATUS_INVALID_PARAMS);
1815 }
1816
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001817 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001818
1819 hci_link_keys_clear(hdev);
1820
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001821 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001822 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001823 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001824 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001825
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001826 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001827 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001828
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001829 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001830 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001831 }
1832
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001833 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001834
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001835 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001836
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001837 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001838}
1839
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001840static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001841 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001842{
1843 struct mgmt_ev_device_unpaired ev;
1844
1845 bacpy(&ev.addr.bdaddr, bdaddr);
1846 ev.addr.type = addr_type;
1847
1848 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001849 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001850}
1851
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001852static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001853 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001854{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001855 struct mgmt_cp_unpair_device *cp = data;
1856 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001857 struct hci_cp_disconnect dc;
1858 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001859 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001860 int err;
1861
Johan Hedberga8a1d192011-11-10 15:54:38 +02001862 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001863 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1864 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001865
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001866 if (!bdaddr_type_is_valid(cp->addr.type))
1867 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1868 MGMT_STATUS_INVALID_PARAMS,
1869 &rp, sizeof(rp));
1870
Johan Hedberg118da702013-01-20 14:27:20 +02001871 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1872 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1873 MGMT_STATUS_INVALID_PARAMS,
1874 &rp, sizeof(rp));
1875
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001876 hci_dev_lock(hdev);
1877
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001878 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001879 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001880 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001881 goto unlock;
1882 }
1883
Andre Guedes591f47f2012-04-24 21:02:49 -03001884 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001885 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1886 else
1887 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001888
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001889 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001890 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001891 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001892 goto unlock;
1893 }
1894
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001895 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001896 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001897 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001898 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001899 else
1900 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001901 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001902 } else {
1903 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001904 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001905
Johan Hedberga8a1d192011-11-10 15:54:38 +02001906 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001907 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001908 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001909 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001910 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001911 }
1912
Johan Hedberg124f6e32012-02-09 13:50:12 +02001913 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001914 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001915 if (!cmd) {
1916 err = -ENOMEM;
1917 goto unlock;
1918 }
1919
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001920 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001921 dc.reason = 0x13; /* Remote User Terminated Connection */
1922 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1923 if (err < 0)
1924 mgmt_pending_remove(cmd);
1925
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001926unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001927 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001928 return err;
1929}
1930
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001931static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001932 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001933{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001934 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001935 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001936 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001937 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001938 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001939 int err;
1940
1941 BT_DBG("");
1942
Johan Hedberg06a63b12013-01-20 14:27:21 +02001943 memset(&rp, 0, sizeof(rp));
1944 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1945 rp.addr.type = cp->addr.type;
1946
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001947 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001948 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1949 MGMT_STATUS_INVALID_PARAMS,
1950 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001951
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001952 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001953
1954 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001955 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1956 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001957 goto failed;
1958 }
1959
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001960 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001961 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1962 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001963 goto failed;
1964 }
1965
Andre Guedes591f47f2012-04-24 21:02:49 -03001966 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001967 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1968 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001969 else
1970 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001971
Vishal Agarwalf9607272012-06-13 05:32:43 +05301972 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001973 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1974 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001975 goto failed;
1976 }
1977
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001978 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001979 if (!cmd) {
1980 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001981 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001982 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001983
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001984 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001985 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001986
1987 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1988 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001989 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001990
1991failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001992 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001993 return err;
1994}
1995
Andre Guedes57c14772012-04-24 21:02:50 -03001996static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001997{
1998 switch (link_type) {
1999 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002000 switch (addr_type) {
2001 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002002 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002003
Johan Hedberg48264f02011-11-09 13:58:58 +02002004 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002005 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002006 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002007 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002008
Johan Hedberg4c659c32011-11-07 23:13:39 +02002009 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002010 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002011 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002012 }
2013}
2014
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2016 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002017{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002018 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002019 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002020 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002021 int err;
2022 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002023
2024 BT_DBG("");
2025
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002026 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002027
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002028 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002029 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002030 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002031 goto unlock;
2032 }
2033
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002034 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002035 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2036 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002037 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002038 }
2039
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002040 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002041 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002042 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002043 err = -ENOMEM;
2044 goto unlock;
2045 }
2046
Johan Hedberg2784eb42011-01-21 13:56:35 +02002047 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002048 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002049 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2050 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002051 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002052 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002053 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002054 continue;
2055 i++;
2056 }
2057
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002058 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002059
Johan Hedberg4c659c32011-11-07 23:13:39 +02002060 /* Recalculate length in case of filtered SCO connections, etc */
2061 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002063 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002064 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002065
Johan Hedberga38528f2011-01-22 06:46:43 +02002066 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002067
2068unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002069 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002070 return err;
2071}
2072
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002073static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002074 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002075{
2076 struct pending_cmd *cmd;
2077 int err;
2078
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002079 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002080 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002081 if (!cmd)
2082 return -ENOMEM;
2083
Johan Hedbergd8457692012-02-17 14:24:57 +02002084 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002085 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002086 if (err < 0)
2087 mgmt_pending_remove(cmd);
2088
2089 return err;
2090}
2091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002094{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002095 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002096 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002097 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002098 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002099 int err;
2100
2101 BT_DBG("");
2102
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002103 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002104
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002105 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002106 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002107 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002108 goto failed;
2109 }
2110
Johan Hedbergd8457692012-02-17 14:24:57 +02002111 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002112 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002113 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002114 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002115 goto failed;
2116 }
2117
2118 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002119 struct mgmt_cp_pin_code_neg_reply ncp;
2120
2121 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002122
2123 BT_ERR("PIN code is not 16 bytes long");
2124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002125 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002126 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002127 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002128 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002129
2130 goto failed;
2131 }
2132
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002133 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002134 if (!cmd) {
2135 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002136 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002137 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002138
Johan Hedbergd8457692012-02-17 14:24:57 +02002139 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002141 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142
2143 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2144 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002145 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002146
2147failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002148 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002149 return err;
2150}
2151
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002152static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2153 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002154{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002155 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002156
2157 BT_DBG("");
2158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002159 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002160
2161 hdev->io_capability = cp->io_capability;
2162
2163 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002164 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002166 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002167
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002168 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2169 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002170}
2171
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002172static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002173{
2174 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002175 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002177 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002178 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2179 continue;
2180
Johan Hedberge9a416b2011-02-19 12:05:56 -03002181 if (cmd->user_data != conn)
2182 continue;
2183
2184 return cmd;
2185 }
2186
2187 return NULL;
2188}
2189
2190static void pairing_complete(struct pending_cmd *cmd, u8 status)
2191{
2192 struct mgmt_rp_pair_device rp;
2193 struct hci_conn *conn = cmd->user_data;
2194
Johan Hedbergba4e5642011-11-11 00:07:34 +02002195 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002196 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002197
Johan Hedbergaee9b212012-02-18 15:07:59 +02002198 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002200
2201 /* So we don't get further callbacks for this connection */
2202 conn->connect_cfm_cb = NULL;
2203 conn->security_cfm_cb = NULL;
2204 conn->disconn_cfm_cb = NULL;
2205
David Herrmann76a68ba2013-04-06 20:28:37 +02002206 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002207
Johan Hedberga664b5b2011-02-19 12:06:02 -03002208 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002209}
2210
2211static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2212{
2213 struct pending_cmd *cmd;
2214
2215 BT_DBG("status %u", status);
2216
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002217 cmd = find_pairing(conn);
2218 if (!cmd)
2219 BT_DBG("Unable to find a pending command");
2220 else
Johan Hedberge2113262012-02-18 15:20:03 +02002221 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002222}
2223
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302224static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2225{
2226 struct pending_cmd *cmd;
2227
2228 BT_DBG("status %u", status);
2229
2230 if (!status)
2231 return;
2232
2233 cmd = find_pairing(conn);
2234 if (!cmd)
2235 BT_DBG("Unable to find a pending command");
2236 else
2237 pairing_complete(cmd, mgmt_status(status));
2238}
2239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002240static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002241 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002242{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002243 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002244 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002245 struct pending_cmd *cmd;
2246 u8 sec_level, auth_type;
2247 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002248 int err;
2249
2250 BT_DBG("");
2251
Szymon Jancf950a30e2013-01-18 12:48:07 +01002252 memset(&rp, 0, sizeof(rp));
2253 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2254 rp.addr.type = cp->addr.type;
2255
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002256 if (!bdaddr_type_is_valid(cp->addr.type))
2257 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2258 MGMT_STATUS_INVALID_PARAMS,
2259 &rp, sizeof(rp));
2260
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002261 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002262
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002263 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002264 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2265 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002266 goto unlock;
2267 }
2268
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002269 sec_level = BT_SECURITY_MEDIUM;
2270 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002271 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002272 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002273 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002274
Andre Guedes591f47f2012-04-24 21:02:49 -03002275 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002276 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2277 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002278 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002279 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2280 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002281
Ville Tervo30e76272011-02-22 16:10:53 -03002282 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002283 int status;
2284
2285 if (PTR_ERR(conn) == -EBUSY)
2286 status = MGMT_STATUS_BUSY;
2287 else
2288 status = MGMT_STATUS_CONNECT_FAILED;
2289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002290 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002291 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002292 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002293 goto unlock;
2294 }
2295
2296 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002297 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002298 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002299 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002300 goto unlock;
2301 }
2302
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002303 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002304 if (!cmd) {
2305 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002306 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002307 goto unlock;
2308 }
2309
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002310 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002311 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002312 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302313 else
2314 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002315
Johan Hedberge9a416b2011-02-19 12:05:56 -03002316 conn->security_cfm_cb = pairing_complete_cb;
2317 conn->disconn_cfm_cb = pairing_complete_cb;
2318 conn->io_capability = cp->io_cap;
2319 cmd->user_data = conn;
2320
2321 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002322 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002323 pairing_complete(cmd, 0);
2324
2325 err = 0;
2326
2327unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002328 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002329 return err;
2330}
2331
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002332static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2333 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002334{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002335 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002336 struct pending_cmd *cmd;
2337 struct hci_conn *conn;
2338 int err;
2339
2340 BT_DBG("");
2341
Johan Hedberg28424702012-02-02 04:02:29 +02002342 hci_dev_lock(hdev);
2343
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002344 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002345 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002346 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002347 goto unlock;
2348 }
2349
Johan Hedberg28424702012-02-02 04:02:29 +02002350 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2351 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002352 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002354 goto unlock;
2355 }
2356
2357 conn = cmd->user_data;
2358
2359 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002362 goto unlock;
2363 }
2364
2365 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002367 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002368 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002369unlock:
2370 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002371 return err;
2372}
2373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002375 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002376 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002377{
Johan Hedberga5c29682011-02-19 12:05:57 -03002378 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002379 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002380 int err;
2381
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002382 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002383
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002384 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002385 err = cmd_complete(sk, hdev->id, mgmt_op,
2386 MGMT_STATUS_NOT_POWERED, addr,
2387 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002388 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002389 }
2390
Johan Hedberg1707c602013-03-15 17:07:15 -05002391 if (addr->type == BDADDR_BREDR)
2392 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002393 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002394 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002395
Johan Hedberg272d90d2012-02-09 15:26:12 +02002396 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002397 err = cmd_complete(sk, hdev->id, mgmt_op,
2398 MGMT_STATUS_NOT_CONNECTED, addr,
2399 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002400 goto done;
2401 }
2402
Johan Hedberg1707c602013-03-15 17:07:15 -05002403 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002404 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002405 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002406
Brian Gix5fe57d92011-12-21 16:12:13 -08002407 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002408 err = cmd_complete(sk, hdev->id, mgmt_op,
2409 MGMT_STATUS_SUCCESS, addr,
2410 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002411 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002412 err = cmd_complete(sk, hdev->id, mgmt_op,
2413 MGMT_STATUS_FAILED, addr,
2414 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002415
Brian Gix47c15e22011-11-16 13:53:14 -08002416 goto done;
2417 }
2418
Johan Hedberg1707c602013-03-15 17:07:15 -05002419 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002420 if (!cmd) {
2421 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002422 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002423 }
2424
Brian Gix0df4c182011-11-16 13:53:13 -08002425 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002426 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2427 struct hci_cp_user_passkey_reply cp;
2428
Johan Hedberg1707c602013-03-15 17:07:15 -05002429 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002430 cp.passkey = passkey;
2431 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2432 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002433 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2434 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002435
Johan Hedberga664b5b2011-02-19 12:06:02 -03002436 if (err < 0)
2437 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002438
Brian Gix0df4c182011-11-16 13:53:13 -08002439done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002440 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002441 return err;
2442}
2443
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302444static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2445 void *data, u16 len)
2446{
2447 struct mgmt_cp_pin_code_neg_reply *cp = data;
2448
2449 BT_DBG("");
2450
Johan Hedberg1707c602013-03-15 17:07:15 -05002451 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302452 MGMT_OP_PIN_CODE_NEG_REPLY,
2453 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2454}
2455
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002456static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2457 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002458{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002459 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002460
2461 BT_DBG("");
2462
2463 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002464 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002465 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002466
Johan Hedberg1707c602013-03-15 17:07:15 -05002467 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002468 MGMT_OP_USER_CONFIRM_REPLY,
2469 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002470}
2471
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002472static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002474{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002475 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002476
2477 BT_DBG("");
2478
Johan Hedberg1707c602013-03-15 17:07:15 -05002479 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2481 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002482}
2483
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002484static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2485 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002486{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002487 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002488
2489 BT_DBG("");
2490
Johan Hedberg1707c602013-03-15 17:07:15 -05002491 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002492 MGMT_OP_USER_PASSKEY_REPLY,
2493 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002494}
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002498{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002499 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002500
2501 BT_DBG("");
2502
Johan Hedberg1707c602013-03-15 17:07:15 -05002503 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002504 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2505 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002506}
2507
Johan Hedberg13928972013-03-15 17:07:00 -05002508static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002509{
Johan Hedberg13928972013-03-15 17:07:00 -05002510 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002511 struct hci_cp_write_local_name cp;
2512
Johan Hedberg13928972013-03-15 17:07:00 -05002513 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002514
Johan Hedberg890ea892013-03-15 17:06:52 -05002515 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002516}
2517
Johan Hedberg13928972013-03-15 17:07:00 -05002518static void set_name_complete(struct hci_dev *hdev, u8 status)
2519{
2520 struct mgmt_cp_set_local_name *cp;
2521 struct pending_cmd *cmd;
2522
2523 BT_DBG("status 0x%02x", status);
2524
2525 hci_dev_lock(hdev);
2526
2527 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2528 if (!cmd)
2529 goto unlock;
2530
2531 cp = cmd->param;
2532
2533 if (status)
2534 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2535 mgmt_status(status));
2536 else
2537 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2538 cp, sizeof(*cp));
2539
2540 mgmt_pending_remove(cmd);
2541
2542unlock:
2543 hci_dev_unlock(hdev);
2544}
2545
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002546static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002548{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002549 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002550 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002551 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002552 int err;
2553
2554 BT_DBG("");
2555
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002556 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002557
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002558 /* If the old values are the same as the new ones just return a
2559 * direct command complete event.
2560 */
2561 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2562 !memcmp(hdev->short_name, cp->short_name,
2563 sizeof(hdev->short_name))) {
2564 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2565 data, len);
2566 goto failed;
2567 }
2568
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002569 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002570
Johan Hedbergb5235a62012-02-21 14:32:24 +02002571 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002572 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002573
2574 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002575 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002576 if (err < 0)
2577 goto failed;
2578
2579 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002581
Johan Hedbergb5235a62012-02-21 14:32:24 +02002582 goto failed;
2583 }
2584
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002585 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002586 if (!cmd) {
2587 err = -ENOMEM;
2588 goto failed;
2589 }
2590
Johan Hedberg13928972013-03-15 17:07:00 -05002591 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2592
Johan Hedberg890ea892013-03-15 17:06:52 -05002593 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002594
2595 if (lmp_bredr_capable(hdev)) {
2596 update_name(&req);
2597 update_eir(&req);
2598 }
2599
2600 if (lmp_le_capable(hdev))
2601 hci_update_ad(&req);
2602
Johan Hedberg13928972013-03-15 17:07:00 -05002603 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002604 if (err < 0)
2605 mgmt_pending_remove(cmd);
2606
2607failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002608 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002609 return err;
2610}
2611
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002612static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002613 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002614{
Szymon Jancc35938b2011-03-22 13:12:21 +01002615 struct pending_cmd *cmd;
2616 int err;
2617
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002619
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002620 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002621
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002622 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002623 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002624 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002625 goto unlock;
2626 }
2627
Andre Guedes9a1a1992012-07-24 15:03:48 -03002628 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002631 goto unlock;
2632 }
2633
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002634 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002635 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002636 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002637 goto unlock;
2638 }
2639
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002640 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002641 if (!cmd) {
2642 err = -ENOMEM;
2643 goto unlock;
2644 }
2645
2646 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2647 if (err < 0)
2648 mgmt_pending_remove(cmd);
2649
2650unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002651 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002652 return err;
2653}
2654
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002655static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002656 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002657{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002658 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002659 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002660 int err;
2661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002663
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002664 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002665
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002666 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002667 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002668 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002669 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002670 else
Szymon Janca6785be2012-12-13 15:11:21 +01002671 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002673 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002674 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002675
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002676 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002677 return err;
2678}
2679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002680static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002681 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002682{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002683 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002684 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002685 int err;
2686
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002687 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002688
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002689 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002690
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002691 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002692 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002693 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002694 else
Szymon Janca6785be2012-12-13 15:11:21 +01002695 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002696
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002697 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002698 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002699
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002700 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002701 return err;
2702}
2703
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002704static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2705{
2706 struct pending_cmd *cmd;
2707 u8 type;
2708 int err;
2709
2710 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2711
2712 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2713 if (!cmd)
2714 return -ENOENT;
2715
2716 type = hdev->discovery.type;
2717
2718 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2719 &type, sizeof(type));
2720 mgmt_pending_remove(cmd);
2721
2722 return err;
2723}
2724
Andre Guedes7c307722013-04-30 15:29:28 -03002725static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2726{
2727 BT_DBG("status %d", status);
2728
2729 if (status) {
2730 hci_dev_lock(hdev);
2731 mgmt_start_discovery_failed(hdev, status);
2732 hci_dev_unlock(hdev);
2733 return;
2734 }
2735
2736 hci_dev_lock(hdev);
2737 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2738 hci_dev_unlock(hdev);
2739
2740 switch (hdev->discovery.type) {
2741 case DISCOV_TYPE_LE:
2742 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002743 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002744 break;
2745
2746 case DISCOV_TYPE_INTERLEAVED:
2747 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002748 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002749 break;
2750
2751 case DISCOV_TYPE_BREDR:
2752 break;
2753
2754 default:
2755 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2756 }
2757}
2758
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002759static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002760 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002761{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002762 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002763 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002764 struct hci_cp_le_set_scan_param param_cp;
2765 struct hci_cp_le_set_scan_enable enable_cp;
2766 struct hci_cp_inquiry inq_cp;
2767 struct hci_request req;
2768 /* General inquiry access code (GIAC) */
2769 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002770 int err;
2771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002772 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002773
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002774 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002775
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002776 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002777 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002778 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002779 goto failed;
2780 }
2781
Andre Guedes642be6c2012-03-21 00:03:37 -03002782 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2783 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2784 MGMT_STATUS_BUSY);
2785 goto failed;
2786 }
2787
Johan Hedbergff9ef572012-01-04 14:23:45 +02002788 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002789 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002790 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002791 goto failed;
2792 }
2793
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002794 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002795 if (!cmd) {
2796 err = -ENOMEM;
2797 goto failed;
2798 }
2799
Andre Guedes4aab14e2012-02-17 20:39:36 -03002800 hdev->discovery.type = cp->type;
2801
Andre Guedes7c307722013-04-30 15:29:28 -03002802 hci_req_init(&req, hdev);
2803
Andre Guedes4aab14e2012-02-17 20:39:36 -03002804 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002805 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002806 if (!lmp_bredr_capable(hdev)) {
2807 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2808 MGMT_STATUS_NOT_SUPPORTED);
2809 mgmt_pending_remove(cmd);
2810 goto failed;
2811 }
2812
Andre Guedes7c307722013-04-30 15:29:28 -03002813 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2814 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2815 MGMT_STATUS_BUSY);
2816 mgmt_pending_remove(cmd);
2817 goto failed;
2818 }
2819
2820 hci_inquiry_cache_flush(hdev);
2821
2822 memset(&inq_cp, 0, sizeof(inq_cp));
2823 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002824 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002825 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002826 break;
2827
2828 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002829 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002830 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002831 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2832 MGMT_STATUS_NOT_SUPPORTED);
2833 mgmt_pending_remove(cmd);
2834 goto failed;
2835 }
2836
Andre Guedes7c307722013-04-30 15:29:28 -03002837 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
2838 !lmp_bredr_capable(hdev)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002839 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2840 MGMT_STATUS_NOT_SUPPORTED);
2841 mgmt_pending_remove(cmd);
2842 goto failed;
2843 }
2844
Andre Guedes7c307722013-04-30 15:29:28 -03002845 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2846 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2847 MGMT_STATUS_REJECTED);
2848 mgmt_pending_remove(cmd);
2849 goto failed;
2850 }
2851
2852 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2853 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2854 MGMT_STATUS_BUSY);
2855 mgmt_pending_remove(cmd);
2856 goto failed;
2857 }
2858
2859 memset(&param_cp, 0, sizeof(param_cp));
2860 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002861 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2862 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002863 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2864 &param_cp);
2865
2866 memset(&enable_cp, 0, sizeof(enable_cp));
2867 enable_cp.enable = LE_SCAN_ENABLE;
2868 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2869 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2870 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002871 break;
2872
Andre Guedesf39799f2012-02-17 20:39:35 -03002873 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002874 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2875 MGMT_STATUS_INVALID_PARAMS);
2876 mgmt_pending_remove(cmd);
2877 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002878 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002879
Andre Guedes7c307722013-04-30 15:29:28 -03002880 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002881 if (err < 0)
2882 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002883 else
2884 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002885
2886failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002887 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002888 return err;
2889}
2890
Andre Guedes1183fdc2013-04-30 15:29:35 -03002891static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2892{
2893 struct pending_cmd *cmd;
2894 int err;
2895
2896 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2897 if (!cmd)
2898 return -ENOENT;
2899
2900 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2901 &hdev->discovery.type, sizeof(hdev->discovery.type));
2902 mgmt_pending_remove(cmd);
2903
2904 return err;
2905}
2906
Andre Guedes0e05bba2013-04-30 15:29:33 -03002907static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2908{
2909 BT_DBG("status %d", status);
2910
2911 hci_dev_lock(hdev);
2912
2913 if (status) {
2914 mgmt_stop_discovery_failed(hdev, status);
2915 goto unlock;
2916 }
2917
2918 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2919
2920unlock:
2921 hci_dev_unlock(hdev);
2922}
2923
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002924static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002925 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002926{
Johan Hedbergd9306502012-02-20 23:25:18 +02002927 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002928 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002929 struct hci_cp_remote_name_req_cancel cp;
2930 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002931 struct hci_request req;
2932 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002933 int err;
2934
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002935 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002936
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002937 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002938
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002939 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002940 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002941 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2942 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002943 goto unlock;
2944 }
2945
2946 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002947 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002948 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2949 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002950 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002951 }
2952
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002953 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002954 if (!cmd) {
2955 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002956 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002957 }
2958
Andre Guedes0e05bba2013-04-30 15:29:33 -03002959 hci_req_init(&req, hdev);
2960
Andre Guedese0d9727e2012-03-20 15:15:36 -03002961 switch (hdev->discovery.state) {
2962 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002963 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2964 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2965 } else {
2966 cancel_delayed_work(&hdev->le_scan_disable);
2967
2968 memset(&enable_cp, 0, sizeof(enable_cp));
2969 enable_cp.enable = LE_SCAN_DISABLE;
2970 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2971 sizeof(enable_cp), &enable_cp);
2972 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002973
Andre Guedese0d9727e2012-03-20 15:15:36 -03002974 break;
2975
2976 case DISCOVERY_RESOLVING:
2977 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002978 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002979 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002980 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002981 err = cmd_complete(sk, hdev->id,
2982 MGMT_OP_STOP_DISCOVERY, 0,
2983 &mgmt_cp->type,
2984 sizeof(mgmt_cp->type));
2985 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2986 goto unlock;
2987 }
2988
2989 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002990 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2991 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002992
2993 break;
2994
2995 default:
2996 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002997
2998 mgmt_pending_remove(cmd);
2999 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3000 MGMT_STATUS_FAILED, &mgmt_cp->type,
3001 sizeof(mgmt_cp->type));
3002 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003003 }
3004
Andre Guedes0e05bba2013-04-30 15:29:33 -03003005 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003006 if (err < 0)
3007 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003008 else
3009 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003010
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003011unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003012 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003013 return err;
3014}
3015
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003016static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003017 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003018{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003019 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003020 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003021 int err;
3022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003023 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003024
Johan Hedberg561aafb2012-01-04 13:31:59 +02003025 hci_dev_lock(hdev);
3026
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003027 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003028 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003030 goto failed;
3031 }
3032
Johan Hedberga198e7b2012-02-17 14:27:06 +02003033 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003034 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003035 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003037 goto failed;
3038 }
3039
3040 if (cp->name_known) {
3041 e->name_state = NAME_KNOWN;
3042 list_del(&e->list);
3043 } else {
3044 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003045 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003046 }
3047
Johan Hedberge3846622013-01-09 15:29:33 +02003048 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3049 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003050
3051failed:
3052 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003053 return err;
3054}
3055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003056static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003057 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003058{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003059 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003060 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003061 int err;
3062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003063 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003064
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003065 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003066 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3067 MGMT_STATUS_INVALID_PARAMS,
3068 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003069
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003070 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003071
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003072 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003073 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003074 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003075 else
Szymon Janca6785be2012-12-13 15:11:21 +01003076 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003077
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003078 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003079 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003080
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003081 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003082
3083 return err;
3084}
3085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003089 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003090 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003091 int err;
3092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003093 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003094
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003095 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003096 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3097 MGMT_STATUS_INVALID_PARAMS,
3098 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003099
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003100 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003101
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003102 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003103 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003104 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003105 else
Szymon Janca6785be2012-12-13 15:11:21 +01003106 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003107
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003108 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003109 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003110
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003111 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003112
3113 return err;
3114}
3115
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003116static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3117 u16 len)
3118{
3119 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003120 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003121 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003122 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003123
3124 BT_DBG("%s", hdev->name);
3125
Szymon Jancc72d4b82012-03-16 16:02:57 +01003126 source = __le16_to_cpu(cp->source);
3127
3128 if (source > 0x0002)
3129 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3130 MGMT_STATUS_INVALID_PARAMS);
3131
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003132 hci_dev_lock(hdev);
3133
Szymon Jancc72d4b82012-03-16 16:02:57 +01003134 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003135 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3136 hdev->devid_product = __le16_to_cpu(cp->product);
3137 hdev->devid_version = __le16_to_cpu(cp->version);
3138
3139 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3140
Johan Hedberg890ea892013-03-15 17:06:52 -05003141 hci_req_init(&req, hdev);
3142 update_eir(&req);
3143 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003144
3145 hci_dev_unlock(hdev);
3146
3147 return err;
3148}
3149
Johan Hedberg4375f102013-09-25 13:26:10 +03003150static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3151{
3152 struct cmd_lookup match = { NULL, hdev };
3153
3154 if (status) {
3155 u8 mgmt_err = mgmt_status(status);
3156
3157 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3158 cmd_status_rsp, &mgmt_err);
3159 return;
3160 }
3161
3162 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3163 &match);
3164
3165 new_settings(hdev, match.sk);
3166
3167 if (match.sk)
3168 sock_put(match.sk);
3169}
3170
3171static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3172{
3173 struct mgmt_mode *cp = data;
3174 struct pending_cmd *cmd;
3175 struct hci_request req;
3176 u8 val, enabled;
3177 int err;
3178
3179 BT_DBG("request for %s", hdev->name);
3180
3181 if (!lmp_le_capable(hdev))
3182 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3183 MGMT_STATUS_NOT_SUPPORTED);
3184
3185 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3186 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3187 MGMT_STATUS_REJECTED);
3188
3189 if (cp->val != 0x00 && cp->val != 0x01)
3190 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3191 MGMT_STATUS_INVALID_PARAMS);
3192
3193 hci_dev_lock(hdev);
3194
3195 val = !!cp->val;
3196 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3197
3198 if (!hdev_is_powered(hdev) || val == enabled) {
3199 bool changed = false;
3200
3201 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3202 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3203 changed = true;
3204 }
3205
3206 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3207 if (err < 0)
3208 goto unlock;
3209
3210 if (changed)
3211 err = new_settings(hdev, sk);
3212
3213 goto unlock;
3214 }
3215
3216 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3217 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3218 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3219 MGMT_STATUS_BUSY);
3220 goto unlock;
3221 }
3222
3223 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3224 if (!cmd) {
3225 err = -ENOMEM;
3226 goto unlock;
3227 }
3228
3229 hci_req_init(&req, hdev);
3230
3231 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3232
3233 err = hci_req_run(&req, set_advertising_complete);
3234 if (err < 0)
3235 mgmt_pending_remove(cmd);
3236
3237unlock:
3238 hci_dev_unlock(hdev);
3239 return err;
3240}
3241
Johan Hedberg33e38b32013-03-15 17:07:05 -05003242static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3243{
3244 struct pending_cmd *cmd;
3245
3246 BT_DBG("status 0x%02x", status);
3247
3248 hci_dev_lock(hdev);
3249
3250 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3251 if (!cmd)
3252 goto unlock;
3253
3254 if (status) {
3255 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3256 mgmt_status(status));
3257 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003258 struct mgmt_mode *cp = cmd->param;
3259
3260 if (cp->val)
3261 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3262 else
3263 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3264
Johan Hedberg33e38b32013-03-15 17:07:05 -05003265 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3266 new_settings(hdev, cmd->sk);
3267 }
3268
3269 mgmt_pending_remove(cmd);
3270
3271unlock:
3272 hci_dev_unlock(hdev);
3273}
3274
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003275static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003276 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003277{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003278 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003279 struct pending_cmd *cmd;
3280 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003281 int err;
3282
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003283 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003284
Johan Hedberg1a47aee2013-03-15 17:07:06 -05003285 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003286 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3287 MGMT_STATUS_NOT_SUPPORTED);
3288
Johan Hedberga7e80f22013-01-09 16:05:19 +02003289 if (cp->val != 0x00 && cp->val != 0x01)
3290 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3291 MGMT_STATUS_INVALID_PARAMS);
3292
Johan Hedberg5400c042012-02-21 16:40:33 +02003293 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003294 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003295 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003296
3297 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003298 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003299 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003300
3301 hci_dev_lock(hdev);
3302
Johan Hedberg05cbf292013-03-15 17:07:07 -05003303 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3304 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3305 MGMT_STATUS_BUSY);
3306 goto unlock;
3307 }
3308
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003309 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3310 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3311 hdev);
3312 goto unlock;
3313 }
3314
Johan Hedberg33e38b32013-03-15 17:07:05 -05003315 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3316 data, len);
3317 if (!cmd) {
3318 err = -ENOMEM;
3319 goto unlock;
3320 }
3321
3322 hci_req_init(&req, hdev);
3323
Johan Hedberg406d7802013-03-15 17:07:09 -05003324 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003325
3326 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003327 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003328 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003329 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003330 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003331 }
3332
Johan Hedberg33e38b32013-03-15 17:07:05 -05003333unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003334 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003335
Antti Julkuf6422ec2011-06-22 13:11:56 +03003336 return err;
3337}
3338
Johan Hedberg3f706b72013-01-20 14:27:16 +02003339static bool ltk_is_valid(struct mgmt_ltk_info *key)
3340{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003341 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3342 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003343 if (key->master != 0x00 && key->master != 0x01)
3344 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003345 if (!bdaddr_type_is_le(key->addr.type))
3346 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003347 return true;
3348}
3349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003350static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003351 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003352{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003353 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3354 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003355 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003356
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003357 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003358
3359 expected_len = sizeof(*cp) + key_count *
3360 sizeof(struct mgmt_ltk_info);
3361 if (expected_len != len) {
3362 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003363 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003364 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003365 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003366 }
3367
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003368 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003369
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003370 for (i = 0; i < key_count; i++) {
3371 struct mgmt_ltk_info *key = &cp->keys[i];
3372
Johan Hedberg3f706b72013-01-20 14:27:16 +02003373 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003374 return cmd_status(sk, hdev->id,
3375 MGMT_OP_LOAD_LONG_TERM_KEYS,
3376 MGMT_STATUS_INVALID_PARAMS);
3377 }
3378
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003379 hci_dev_lock(hdev);
3380
3381 hci_smp_ltks_clear(hdev);
3382
3383 for (i = 0; i < key_count; i++) {
3384 struct mgmt_ltk_info *key = &cp->keys[i];
3385 u8 type;
3386
3387 if (key->master)
3388 type = HCI_SMP_LTK;
3389 else
3390 type = HCI_SMP_LTK_SLAVE;
3391
Hemant Gupta4596fde2012-04-16 14:57:40 +05303392 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003393 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003394 type, 0, key->authenticated, key->val,
3395 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003396 }
3397
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003398 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3399 NULL, 0);
3400
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003401 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003402
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003403 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003404}
3405
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003406static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003407 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3408 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003409 bool var_len;
3410 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003411} mgmt_handlers[] = {
3412 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003413 { read_version, false, MGMT_READ_VERSION_SIZE },
3414 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3415 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3416 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3417 { set_powered, false, MGMT_SETTING_SIZE },
3418 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3419 { set_connectable, false, MGMT_SETTING_SIZE },
3420 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3421 { set_pairable, false, MGMT_SETTING_SIZE },
3422 { set_link_security, false, MGMT_SETTING_SIZE },
3423 { set_ssp, false, MGMT_SETTING_SIZE },
3424 { set_hs, false, MGMT_SETTING_SIZE },
3425 { set_le, false, MGMT_SETTING_SIZE },
3426 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3427 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3428 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3429 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3430 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3431 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3432 { disconnect, false, MGMT_DISCONNECT_SIZE },
3433 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3434 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3435 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3436 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3437 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3438 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3439 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3440 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3441 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3442 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3443 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3444 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3445 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3446 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3447 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3448 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3449 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3450 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3451 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003452 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003453 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003454};
3455
3456
Johan Hedberg03811012010-12-08 00:21:06 +02003457int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3458{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003459 void *buf;
3460 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003461 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003462 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003463 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003464 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003465 int err;
3466
3467 BT_DBG("got %zu bytes", msglen);
3468
3469 if (msglen < sizeof(*hdr))
3470 return -EINVAL;
3471
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003472 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003473 if (!buf)
3474 return -ENOMEM;
3475
3476 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3477 err = -EFAULT;
3478 goto done;
3479 }
3480
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003481 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003482 opcode = __le16_to_cpu(hdr->opcode);
3483 index = __le16_to_cpu(hdr->index);
3484 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003485
3486 if (len != msglen - sizeof(*hdr)) {
3487 err = -EINVAL;
3488 goto done;
3489 }
3490
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003491 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003492 hdev = hci_dev_get(index);
3493 if (!hdev) {
3494 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003495 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003496 goto done;
3497 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003498
3499 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3500 err = cmd_status(sk, index, opcode,
3501 MGMT_STATUS_INVALID_INDEX);
3502 goto done;
3503 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003504 }
3505
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003506 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003507 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003508 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003509 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003510 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003511 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003512 }
3513
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003514 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003515 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003516 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003517 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003518 goto done;
3519 }
3520
Johan Hedbergbe22b542012-03-01 22:24:41 +02003521 handler = &mgmt_handlers[opcode];
3522
3523 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003524 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003525 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003526 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003527 goto done;
3528 }
3529
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003530 if (hdev)
3531 mgmt_init_hdev(sk, hdev);
3532
3533 cp = buf + sizeof(*hdr);
3534
Johan Hedbergbe22b542012-03-01 22:24:41 +02003535 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003536 if (err < 0)
3537 goto done;
3538
Johan Hedberg03811012010-12-08 00:21:06 +02003539 err = msglen;
3540
3541done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003542 if (hdev)
3543 hci_dev_put(hdev);
3544
Johan Hedberg03811012010-12-08 00:21:06 +02003545 kfree(buf);
3546 return err;
3547}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003548
Johan Hedberg744cf192011-11-08 20:40:14 +02003549int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003550{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003551 if (!mgmt_valid_hdev(hdev))
3552 return -ENOTSUPP;
3553
Johan Hedberg744cf192011-11-08 20:40:14 +02003554 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003555}
3556
Johan Hedberg744cf192011-11-08 20:40:14 +02003557int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003558{
Johan Hedberg5f159032012-03-02 03:13:19 +02003559 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003560
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003561 if (!mgmt_valid_hdev(hdev))
3562 return -ENOTSUPP;
3563
Johan Hedberg744cf192011-11-08 20:40:14 +02003564 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003565
Johan Hedberg744cf192011-11-08 20:40:14 +02003566 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003567}
3568
Johan Hedberg890ea892013-03-15 17:06:52 -05003569static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003570{
Johan Hedberg890ea892013-03-15 17:06:52 -05003571 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003572 u8 scan = 0;
3573
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003574 /* Ensure that fast connectable is disabled. This function will
3575 * not do anything if the page scan parameters are already what
3576 * they should be.
3577 */
3578 write_fast_connectable(req, false);
3579
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003580 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3581 scan |= SCAN_PAGE;
3582 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3583 scan |= SCAN_INQUIRY;
3584
Johan Hedberg890ea892013-03-15 17:06:52 -05003585 if (scan)
3586 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003587}
3588
Johan Hedberg229ab392013-03-15 17:06:53 -05003589static void powered_complete(struct hci_dev *hdev, u8 status)
3590{
3591 struct cmd_lookup match = { NULL, hdev };
3592
3593 BT_DBG("status 0x%02x", status);
3594
3595 hci_dev_lock(hdev);
3596
3597 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3598
3599 new_settings(hdev, match.sk);
3600
3601 hci_dev_unlock(hdev);
3602
3603 if (match.sk)
3604 sock_put(match.sk);
3605}
3606
Johan Hedberg70da6242013-03-15 17:06:51 -05003607static int powered_update_hci(struct hci_dev *hdev)
3608{
Johan Hedberg890ea892013-03-15 17:06:52 -05003609 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003610 u8 link_sec;
3611
Johan Hedberg890ea892013-03-15 17:06:52 -05003612 hci_req_init(&req, hdev);
3613
Johan Hedberg70da6242013-03-15 17:06:51 -05003614 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3615 !lmp_host_ssp_capable(hdev)) {
3616 u8 ssp = 1;
3617
Johan Hedberg890ea892013-03-15 17:06:52 -05003618 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003619 }
3620
Johan Hedbergc73eee92013-04-19 18:35:21 +03003621 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3622 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003623 struct hci_cp_write_le_host_supported cp;
3624
3625 cp.le = 1;
3626 cp.simul = lmp_le_br_capable(hdev);
3627
3628 /* Check first if we already have the right
3629 * host state (host features set)
3630 */
3631 if (cp.le != lmp_host_le_capable(hdev) ||
3632 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003633 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3634 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003635 }
3636
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003637 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3638 u8 adv = 0x01;
3639
3640 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3641 }
3642
Johan Hedberg70da6242013-03-15 17:06:51 -05003643 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3644 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003645 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3646 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003647
3648 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003649 set_bredr_scan(&req);
3650 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003651 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003652 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003653 }
3654
Johan Hedberg229ab392013-03-15 17:06:53 -05003655 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003656}
3657
Johan Hedberg744cf192011-11-08 20:40:14 +02003658int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003659{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003660 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003661 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3662 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003663 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003664
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003665 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3666 return 0;
3667
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003668 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003669 if (powered_update_hci(hdev) == 0)
3670 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003671
Johan Hedberg229ab392013-03-15 17:06:53 -05003672 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3673 &match);
3674 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003675 }
3676
Johan Hedberg229ab392013-03-15 17:06:53 -05003677 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3678 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3679
3680 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3681 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3682 zero_cod, sizeof(zero_cod), NULL);
3683
3684new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003685 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003686
3687 if (match.sk)
3688 sock_put(match.sk);
3689
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003690 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003691}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003692
Johan Hedberg96570ff2013-05-29 09:51:29 +03003693int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3694{
3695 struct pending_cmd *cmd;
3696 u8 status;
3697
3698 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3699 if (!cmd)
3700 return -ENOENT;
3701
3702 if (err == -ERFKILL)
3703 status = MGMT_STATUS_RFKILLED;
3704 else
3705 status = MGMT_STATUS_FAILED;
3706
3707 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3708
3709 mgmt_pending_remove(cmd);
3710
3711 return err;
3712}
3713
Johan Hedberg744cf192011-11-08 20:40:14 +02003714int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003715{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003716 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003717 bool changed = false;
3718 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003719
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003720 if (discoverable) {
3721 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3722 changed = true;
3723 } else {
3724 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3725 changed = true;
3726 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003727
Johan Hedberged9b5f22012-02-21 20:47:06 +02003728 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003729 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003730
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003731 if (changed)
3732 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003733
Johan Hedberg73f22f62010-12-29 16:00:25 +02003734 if (match.sk)
3735 sock_put(match.sk);
3736
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003737 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003738}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003739
Johan Hedberg744cf192011-11-08 20:40:14 +02003740int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003741{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003742 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003743 bool changed = false;
3744 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003745
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003746 if (connectable) {
3747 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3748 changed = true;
3749 } else {
3750 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3751 changed = true;
3752 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003753
Johan Hedberg2b76f452013-03-15 17:07:04 -05003754 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003755
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003756 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003757 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003758
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003759 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003760}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003761
Johan Hedberg744cf192011-11-08 20:40:14 +02003762int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003763{
Johan Hedbergca69b792011-11-11 18:10:00 +02003764 u8 mgmt_err = mgmt_status(status);
3765
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003766 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003767 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003768 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003769
3770 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003771 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003772 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003773
3774 return 0;
3775}
3776
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003777int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3778 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003779{
Johan Hedberg86742e12011-11-07 23:13:38 +02003780 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003781
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003782 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003783
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003784 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003785 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003786 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003787 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003788 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003789 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003790
Johan Hedberg744cf192011-11-08 20:40:14 +02003791 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003792}
Johan Hedbergf7520542011-01-20 12:34:39 +02003793
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003794int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3795{
3796 struct mgmt_ev_new_long_term_key ev;
3797
3798 memset(&ev, 0, sizeof(ev));
3799
3800 ev.store_hint = persistent;
3801 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003802 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003803 ev.key.authenticated = key->authenticated;
3804 ev.key.enc_size = key->enc_size;
3805 ev.key.ediv = key->ediv;
3806
3807 if (key->type == HCI_SMP_LTK)
3808 ev.key.master = 1;
3809
3810 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3811 memcpy(ev.key.val, key->val, sizeof(key->val));
3812
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003813 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3814 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003815}
3816
Johan Hedbergafc747a2012-01-15 18:11:07 +02003817int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003818 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3819 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003820{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003821 char buf[512];
3822 struct mgmt_ev_device_connected *ev = (void *) buf;
3823 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003824
Johan Hedbergb644ba32012-01-17 21:48:47 +02003825 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003826 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003827
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003828 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003829
Johan Hedbergb644ba32012-01-17 21:48:47 +02003830 if (name_len > 0)
3831 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003832 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003833
3834 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003835 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003836 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003837
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003838 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003839
3840 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003841 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003842}
3843
Johan Hedberg8962ee72011-01-20 12:40:27 +02003844static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3845{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003846 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003847 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003848 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003849
Johan Hedberg88c3df12012-02-09 14:27:38 +02003850 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3851 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003852
Johan Hedbergaee9b212012-02-18 15:07:59 +02003853 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003854 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003855
3856 *sk = cmd->sk;
3857 sock_hold(*sk);
3858
Johan Hedberga664b5b2011-02-19 12:06:02 -03003859 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003860}
3861
Johan Hedberg124f6e32012-02-09 13:50:12 +02003862static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003863{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003864 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003865 struct mgmt_cp_unpair_device *cp = cmd->param;
3866 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003867
3868 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003869 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3870 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003871
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003872 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3873
Johan Hedbergaee9b212012-02-18 15:07:59 +02003874 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003875
3876 mgmt_pending_remove(cmd);
3877}
3878
Johan Hedbergafc747a2012-01-15 18:11:07 +02003879int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003880 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003881{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003882 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003883 struct sock *sk = NULL;
3884 int err;
3885
Johan Hedberg744cf192011-11-08 20:40:14 +02003886 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003887
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003888 bacpy(&ev.addr.bdaddr, bdaddr);
3889 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3890 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003891
Johan Hedbergafc747a2012-01-15 18:11:07 +02003892 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003893 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003894
3895 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003896 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003897
Johan Hedberg124f6e32012-02-09 13:50:12 +02003898 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003899 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003900
Johan Hedberg8962ee72011-01-20 12:40:27 +02003901 return err;
3902}
3903
Johan Hedberg88c3df12012-02-09 14:27:38 +02003904int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003905 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003906{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003907 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003908 struct pending_cmd *cmd;
3909 int err;
3910
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003911 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3912 hdev);
3913
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003914 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003915 if (!cmd)
3916 return -ENOENT;
3917
Johan Hedberg88c3df12012-02-09 14:27:38 +02003918 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003919 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003920
Johan Hedberg88c3df12012-02-09 14:27:38 +02003921 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003922 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003923
Johan Hedberga664b5b2011-02-19 12:06:02 -03003924 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003925
3926 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003927}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003928
Johan Hedberg48264f02011-11-09 13:58:58 +02003929int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003930 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003931{
3932 struct mgmt_ev_connect_failed ev;
3933
Johan Hedberg4c659c32011-11-07 23:13:39 +02003934 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003935 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003936 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003937
Johan Hedberg744cf192011-11-08 20:40:14 +02003938 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003939}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003940
Johan Hedberg744cf192011-11-08 20:40:14 +02003941int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003942{
3943 struct mgmt_ev_pin_code_request ev;
3944
Johan Hedbergd8457692012-02-17 14:24:57 +02003945 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003946 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003947 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003948
Johan Hedberg744cf192011-11-08 20:40:14 +02003949 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003950 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003951}
3952
Johan Hedberg744cf192011-11-08 20:40:14 +02003953int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003954 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003955{
3956 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003957 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003958 int err;
3959
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003960 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003961 if (!cmd)
3962 return -ENOENT;
3963
Johan Hedbergd8457692012-02-17 14:24:57 +02003964 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003965 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003966
Johan Hedbergaee9b212012-02-18 15:07:59 +02003967 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003968 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003969
Johan Hedberga664b5b2011-02-19 12:06:02 -03003970 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003971
3972 return err;
3973}
3974
Johan Hedberg744cf192011-11-08 20:40:14 +02003975int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003976 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003977{
3978 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003979 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003980 int err;
3981
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003982 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003983 if (!cmd)
3984 return -ENOENT;
3985
Johan Hedbergd8457692012-02-17 14:24:57 +02003986 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003987 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003988
Johan Hedbergaee9b212012-02-18 15:07:59 +02003989 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003990 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003991
Johan Hedberga664b5b2011-02-19 12:06:02 -03003992 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003993
3994 return err;
3995}
Johan Hedberga5c29682011-02-19 12:05:57 -03003996
Johan Hedberg744cf192011-11-08 20:40:14 +02003997int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003998 u8 link_type, u8 addr_type, __le32 value,
3999 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004000{
4001 struct mgmt_ev_user_confirm_request ev;
4002
Johan Hedberg744cf192011-11-08 20:40:14 +02004003 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004004
Johan Hedberg272d90d2012-02-09 15:26:12 +02004005 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004006 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004007 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004008 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004009
Johan Hedberg744cf192011-11-08 20:40:14 +02004010 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004011 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004012}
4013
Johan Hedberg272d90d2012-02-09 15:26:12 +02004014int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004015 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004016{
4017 struct mgmt_ev_user_passkey_request ev;
4018
4019 BT_DBG("%s", hdev->name);
4020
Johan Hedberg272d90d2012-02-09 15:26:12 +02004021 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004022 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004023
4024 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004025 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004026}
4027
Brian Gix0df4c182011-11-16 13:53:13 -08004028static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004029 u8 link_type, u8 addr_type, u8 status,
4030 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004031{
4032 struct pending_cmd *cmd;
4033 struct mgmt_rp_user_confirm_reply rp;
4034 int err;
4035
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004036 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004037 if (!cmd)
4038 return -ENOENT;
4039
Johan Hedberg272d90d2012-02-09 15:26:12 +02004040 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004041 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004042 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004043 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004044
Johan Hedberga664b5b2011-02-19 12:06:02 -03004045 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004046
4047 return err;
4048}
4049
Johan Hedberg744cf192011-11-08 20:40:14 +02004050int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004051 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004052{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004053 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004054 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004055}
4056
Johan Hedberg272d90d2012-02-09 15:26:12 +02004057int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004058 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004059{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004060 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004061 status,
4062 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004063}
Johan Hedberg2a611692011-02-19 12:06:00 -03004064
Brian Gix604086b2011-11-23 08:28:33 -08004065int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004066 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004067{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004068 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004069 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004070}
4071
Johan Hedberg272d90d2012-02-09 15:26:12 +02004072int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004073 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004074{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004075 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004076 status,
4077 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004078}
4079
Johan Hedberg92a25252012-09-06 18:39:26 +03004080int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4081 u8 link_type, u8 addr_type, u32 passkey,
4082 u8 entered)
4083{
4084 struct mgmt_ev_passkey_notify ev;
4085
4086 BT_DBG("%s", hdev->name);
4087
4088 bacpy(&ev.addr.bdaddr, bdaddr);
4089 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4090 ev.passkey = __cpu_to_le32(passkey);
4091 ev.entered = entered;
4092
4093 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4094}
4095
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004096int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004097 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004098{
4099 struct mgmt_ev_auth_failed ev;
4100
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004101 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004102 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004103 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004104
Johan Hedberg744cf192011-11-08 20:40:14 +02004105 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004106}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004107
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004108int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4109{
4110 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004111 bool changed = false;
4112 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004113
4114 if (status) {
4115 u8 mgmt_err = mgmt_status(status);
4116 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004117 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004118 return 0;
4119 }
4120
Johan Hedberg47990ea2012-02-22 11:58:37 +02004121 if (test_bit(HCI_AUTH, &hdev->flags)) {
4122 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4123 changed = true;
4124 } else {
4125 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4126 changed = true;
4127 }
4128
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004129 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004130 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004131
Johan Hedberg47990ea2012-02-22 11:58:37 +02004132 if (changed)
4133 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004134
4135 if (match.sk)
4136 sock_put(match.sk);
4137
4138 return err;
4139}
4140
Johan Hedberg890ea892013-03-15 17:06:52 -05004141static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004142{
Johan Hedberg890ea892013-03-15 17:06:52 -05004143 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004144 struct hci_cp_write_eir cp;
4145
Johan Hedberg976eb202012-10-24 21:12:01 +03004146 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004147 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004148
Johan Hedbergc80da272012-02-22 15:38:48 +02004149 memset(hdev->eir, 0, sizeof(hdev->eir));
4150
Johan Hedbergcacaf522012-02-21 00:52:42 +02004151 memset(&cp, 0, sizeof(cp));
4152
Johan Hedberg890ea892013-03-15 17:06:52 -05004153 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004154}
4155
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004156int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004157{
4158 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004159 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004160 bool changed = false;
4161 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004162
4163 if (status) {
4164 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004165
4166 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004167 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004168 err = new_settings(hdev, NULL);
4169
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004170 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4171 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004172
4173 return err;
4174 }
4175
4176 if (enable) {
4177 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4178 changed = true;
4179 } else {
4180 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4181 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004182 }
4183
4184 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4185
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004186 if (changed)
4187 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004188
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004189 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004190 sock_put(match.sk);
4191
Johan Hedberg890ea892013-03-15 17:06:52 -05004192 hci_req_init(&req, hdev);
4193
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004194 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004195 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004196 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004197 clear_eir(&req);
4198
4199 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004200
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004201 return err;
4202}
4203
Johan Hedberg92da6092013-03-15 17:06:55 -05004204static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004205{
4206 struct cmd_lookup *match = data;
4207
Johan Hedberg90e70452012-02-23 23:09:40 +02004208 if (match->sk == NULL) {
4209 match->sk = cmd->sk;
4210 sock_hold(match->sk);
4211 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004212}
4213
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004214int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004215 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004216{
Johan Hedberg90e70452012-02-23 23:09:40 +02004217 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4218 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004219
Johan Hedberg92da6092013-03-15 17:06:55 -05004220 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4221 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4222 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004223
4224 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004225 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4226 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004227
4228 if (match.sk)
4229 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004230
4231 return err;
4232}
4233
Johan Hedberg744cf192011-11-08 20:40:14 +02004234int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004235{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004236 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004237 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004238
Johan Hedberg13928972013-03-15 17:07:00 -05004239 if (status)
4240 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004241
4242 memset(&ev, 0, sizeof(ev));
4243 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004244 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004245
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004246 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004247 if (!cmd) {
4248 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004249
Johan Hedberg13928972013-03-15 17:07:00 -05004250 /* If this is a HCI command related to powering on the
4251 * HCI dev don't send any mgmt signals.
4252 */
4253 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4254 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004255 }
4256
Johan Hedberg13928972013-03-15 17:07:00 -05004257 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4258 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004259}
Szymon Jancc35938b2011-03-22 13:12:21 +01004260
Johan Hedberg744cf192011-11-08 20:40:14 +02004261int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004262 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004263{
4264 struct pending_cmd *cmd;
4265 int err;
4266
Johan Hedberg744cf192011-11-08 20:40:14 +02004267 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004268
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004269 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004270 if (!cmd)
4271 return -ENOENT;
4272
4273 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004274 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4275 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004276 } else {
4277 struct mgmt_rp_read_local_oob_data rp;
4278
4279 memcpy(rp.hash, hash, sizeof(rp.hash));
4280 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4281
Johan Hedberg744cf192011-11-08 20:40:14 +02004282 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004283 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4284 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004285 }
4286
4287 mgmt_pending_remove(cmd);
4288
4289 return err;
4290}
Johan Hedberge17acd42011-03-30 23:57:16 +03004291
Johan Hedberg48264f02011-11-09 13:58:58 +02004292int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004293 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4294 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004295{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004296 char buf[512];
4297 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004298 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004299
Andre Guedes12602d02013-04-30 15:29:40 -03004300 if (!hci_discovery_active(hdev))
4301 return -EPERM;
4302
Johan Hedberg1dc06092012-01-15 21:01:23 +02004303 /* Leave 5 bytes for a potential CoD field */
4304 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004305 return -EINVAL;
4306
Johan Hedberg1dc06092012-01-15 21:01:23 +02004307 memset(buf, 0, sizeof(buf));
4308
Johan Hedberge319d2e2012-01-15 19:51:59 +02004309 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004310 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004311 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004312 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304313 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004314 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304315 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004316
Johan Hedberg1dc06092012-01-15 21:01:23 +02004317 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004318 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004319
Johan Hedberg1dc06092012-01-15 21:01:23 +02004320 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4321 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004322 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004323
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004324 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004325 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004326
Johan Hedberge319d2e2012-01-15 19:51:59 +02004327 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004328}
Johan Hedberga88a9652011-03-30 13:18:12 +03004329
Johan Hedbergb644ba32012-01-17 21:48:47 +02004330int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004331 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004332{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004333 struct mgmt_ev_device_found *ev;
4334 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4335 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004336
Johan Hedbergb644ba32012-01-17 21:48:47 +02004337 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004338
Johan Hedbergb644ba32012-01-17 21:48:47 +02004339 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004340
Johan Hedbergb644ba32012-01-17 21:48:47 +02004341 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004342 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004343 ev->rssi = rssi;
4344
4345 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004346 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004347
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004348 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004349
Johan Hedberg053c7e02012-02-04 00:06:00 +02004350 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004351 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004352}
Johan Hedberg314b2382011-04-27 10:29:57 -04004353
Johan Hedberg744cf192011-11-08 20:40:14 +02004354int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004355{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004356 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004357 struct pending_cmd *cmd;
4358
Andre Guedes343fb142011-11-22 17:14:19 -03004359 BT_DBG("%s discovering %u", hdev->name, discovering);
4360
Johan Hedberg164a6e72011-11-01 17:06:44 +02004361 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004362 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004363 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004364 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004365
4366 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004367 u8 type = hdev->discovery.type;
4368
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004369 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4370 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004371 mgmt_pending_remove(cmd);
4372 }
4373
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004374 memset(&ev, 0, sizeof(ev));
4375 ev.type = hdev->discovery.type;
4376 ev.discovering = discovering;
4377
4378 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004379}
Antti Julku5e762442011-08-25 16:48:02 +03004380
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004381int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004382{
4383 struct pending_cmd *cmd;
4384 struct mgmt_ev_device_blocked ev;
4385
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004386 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004387
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004388 bacpy(&ev.addr.bdaddr, bdaddr);
4389 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004390
Johan Hedberg744cf192011-11-08 20:40:14 +02004391 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004392 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004393}
4394
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004395int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004396{
4397 struct pending_cmd *cmd;
4398 struct mgmt_ev_device_unblocked ev;
4399
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004400 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004401
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004402 bacpy(&ev.addr.bdaddr, bdaddr);
4403 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004404
Johan Hedberg744cf192011-11-08 20:40:14 +02004405 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004406 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004407}