blob: dd15491f2374caad5fbe5a12b5ca99a351d6602b [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 Hedberg84bde9d2012-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 Hedberg84bde9d2012-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;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001340
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001341 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001342
Marcel Holtmann848566b2013-10-01 22:59:22 -07001343 if (!lmp_bredr_capable(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001344 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001345 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001346
Johan Hedberga7e80f22013-01-09 16:05:19 +02001347 if (cp->val != 0x00 && cp->val != 0x01)
1348 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1349 MGMT_STATUS_INVALID_PARAMS);
1350
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001351 if (cp->val)
1352 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1353 else
1354 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1355
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001356 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001357}
1358
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001359static void le_enable_complete(struct hci_dev *hdev, u8 status)
1360{
1361 struct cmd_lookup match = { NULL, hdev };
1362
1363 if (status) {
1364 u8 mgmt_err = mgmt_status(status);
1365
1366 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1367 &mgmt_err);
1368 return;
1369 }
1370
1371 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1372
1373 new_settings(hdev, match.sk);
1374
1375 if (match.sk)
1376 sock_put(match.sk);
1377}
1378
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001379static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001380{
1381 struct mgmt_mode *cp = data;
1382 struct hci_cp_write_le_host_supported hci_cp;
1383 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001384 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001385 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001386 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001387
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001388 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001389
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001390 if (!lmp_le_capable(hdev))
1391 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1392 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001393
Johan Hedberga7e80f22013-01-09 16:05:19 +02001394 if (cp->val != 0x00 && cp->val != 0x01)
1395 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1396 MGMT_STATUS_INVALID_PARAMS);
1397
Johan Hedbergc73eee92013-04-19 18:35:21 +03001398 /* LE-only devices do not allow toggling LE on/off */
1399 if (!lmp_bredr_capable(hdev))
1400 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1401 MGMT_STATUS_REJECTED);
1402
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001403 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001404
1405 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001406 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001407
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001408 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001409 bool changed = false;
1410
1411 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1412 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1413 changed = true;
1414 }
1415
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001416 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1417 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1418 changed = true;
1419 }
1420
Johan Hedberg06199cf2012-02-22 16:37:11 +02001421 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1422 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001423 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001424
1425 if (changed)
1426 err = new_settings(hdev, sk);
1427
Johan Hedberg1de028c2012-02-29 19:55:35 -08001428 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001429 }
1430
Johan Hedberg4375f102013-09-25 13:26:10 +03001431 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1432 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001433 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001434 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001435 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001436 }
1437
1438 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1439 if (!cmd) {
1440 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001441 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001442 }
1443
1444 memset(&hci_cp, 0, sizeof(hci_cp));
1445
1446 if (val) {
1447 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001448 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001449 }
1450
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001451 hci_req_init(&req, hdev);
1452
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001453 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1454 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1455
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001456 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1457 &hci_cp);
1458
1459 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301460 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001461 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001462
Johan Hedberg1de028c2012-02-29 19:55:35 -08001463unlock:
1464 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001465 return err;
1466}
1467
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001468/* This is a helper function to test for pending mgmt commands that can
1469 * cause CoD or EIR HCI commands. We can only allow one such pending
1470 * mgmt command at a time since otherwise we cannot easily track what
1471 * the current values are, will be, and based on that calculate if a new
1472 * HCI command needs to be sent and if yes with what value.
1473 */
1474static bool pending_eir_or_class(struct hci_dev *hdev)
1475{
1476 struct pending_cmd *cmd;
1477
1478 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1479 switch (cmd->opcode) {
1480 case MGMT_OP_ADD_UUID:
1481 case MGMT_OP_REMOVE_UUID:
1482 case MGMT_OP_SET_DEV_CLASS:
1483 case MGMT_OP_SET_POWERED:
1484 return true;
1485 }
1486 }
1487
1488 return false;
1489}
1490
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001491static const u8 bluetooth_base_uuid[] = {
1492 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1493 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1494};
1495
1496static u8 get_uuid_size(const u8 *uuid)
1497{
1498 u32 val;
1499
1500 if (memcmp(uuid, bluetooth_base_uuid, 12))
1501 return 128;
1502
1503 val = get_unaligned_le32(&uuid[12]);
1504 if (val > 0xffff)
1505 return 32;
1506
1507 return 16;
1508}
1509
Johan Hedberg92da6092013-03-15 17:06:55 -05001510static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1511{
1512 struct pending_cmd *cmd;
1513
1514 hci_dev_lock(hdev);
1515
1516 cmd = mgmt_pending_find(mgmt_op, hdev);
1517 if (!cmd)
1518 goto unlock;
1519
1520 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1521 hdev->dev_class, 3);
1522
1523 mgmt_pending_remove(cmd);
1524
1525unlock:
1526 hci_dev_unlock(hdev);
1527}
1528
1529static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1530{
1531 BT_DBG("status 0x%02x", status);
1532
1533 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1534}
1535
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001536static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001537{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001538 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001539 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001540 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001541 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001542 int err;
1543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001544 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001545
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001546 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001547
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001548 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001550 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001551 goto failed;
1552 }
1553
Andre Guedes92c4c202012-06-07 19:05:44 -03001554 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001555 if (!uuid) {
1556 err = -ENOMEM;
1557 goto failed;
1558 }
1559
1560 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001561 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001562 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001563
Johan Hedbergde66aa62013-01-27 00:31:27 +02001564 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001565
Johan Hedberg890ea892013-03-15 17:06:52 -05001566 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001567
Johan Hedberg890ea892013-03-15 17:06:52 -05001568 update_class(&req);
1569 update_eir(&req);
1570
Johan Hedberg92da6092013-03-15 17:06:55 -05001571 err = hci_req_run(&req, add_uuid_complete);
1572 if (err < 0) {
1573 if (err != -ENODATA)
1574 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001575
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001576 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001577 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001578 goto failed;
1579 }
1580
1581 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001582 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001583 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001584 goto failed;
1585 }
1586
1587 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001588
1589failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001590 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001591 return err;
1592}
1593
Johan Hedberg24b78d02012-02-23 23:24:30 +02001594static bool enable_service_cache(struct hci_dev *hdev)
1595{
1596 if (!hdev_is_powered(hdev))
1597 return false;
1598
1599 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001600 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1601 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001602 return true;
1603 }
1604
1605 return false;
1606}
1607
Johan Hedberg92da6092013-03-15 17:06:55 -05001608static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1609{
1610 BT_DBG("status 0x%02x", status);
1611
1612 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1613}
1614
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001615static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001616 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001617{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001618 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001619 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001620 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001621 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 -05001622 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001623 int err, found;
1624
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001625 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001626
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001627 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001628
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001629 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001630 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001631 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001632 goto unlock;
1633 }
1634
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001635 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1636 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001637
Johan Hedberg24b78d02012-02-23 23:24:30 +02001638 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001639 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001640 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001641 goto unlock;
1642 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001643
Johan Hedberg9246a862012-02-23 21:33:16 +02001644 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001645 }
1646
1647 found = 0;
1648
Johan Hedberg056341c2013-01-27 00:31:30 +02001649 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001650 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1651 continue;
1652
1653 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001654 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001655 found++;
1656 }
1657
1658 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001659 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001660 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001661 goto unlock;
1662 }
1663
Johan Hedberg9246a862012-02-23 21:33:16 +02001664update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001665 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001666
Johan Hedberg890ea892013-03-15 17:06:52 -05001667 update_class(&req);
1668 update_eir(&req);
1669
Johan Hedberg92da6092013-03-15 17:06:55 -05001670 err = hci_req_run(&req, remove_uuid_complete);
1671 if (err < 0) {
1672 if (err != -ENODATA)
1673 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001674
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001675 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001676 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001677 goto unlock;
1678 }
1679
1680 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001681 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001682 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001683 goto unlock;
1684 }
1685
1686 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001687
1688unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001689 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001690 return err;
1691}
1692
Johan Hedberg92da6092013-03-15 17:06:55 -05001693static void set_class_complete(struct hci_dev *hdev, u8 status)
1694{
1695 BT_DBG("status 0x%02x", status);
1696
1697 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1698}
1699
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001700static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001701 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001702{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001703 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001704 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001705 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001706 int err;
1707
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001708 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001709
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001710 if (!lmp_bredr_capable(hdev))
1711 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1712 MGMT_STATUS_NOT_SUPPORTED);
1713
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001714 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001715
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001716 if (pending_eir_or_class(hdev)) {
1717 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1718 MGMT_STATUS_BUSY);
1719 goto unlock;
1720 }
1721
1722 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1723 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1724 MGMT_STATUS_INVALID_PARAMS);
1725 goto unlock;
1726 }
1727
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001728 hdev->major_class = cp->major;
1729 hdev->minor_class = cp->minor;
1730
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001731 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001732 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001733 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001734 goto unlock;
1735 }
1736
Johan Hedberg890ea892013-03-15 17:06:52 -05001737 hci_req_init(&req, hdev);
1738
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001739 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001740 hci_dev_unlock(hdev);
1741 cancel_delayed_work_sync(&hdev->service_cache);
1742 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001743 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001744 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001745
Johan Hedberg890ea892013-03-15 17:06:52 -05001746 update_class(&req);
1747
Johan Hedberg92da6092013-03-15 17:06:55 -05001748 err = hci_req_run(&req, set_class_complete);
1749 if (err < 0) {
1750 if (err != -ENODATA)
1751 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001752
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001753 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001754 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001755 goto unlock;
1756 }
1757
1758 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001759 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001760 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001761 goto unlock;
1762 }
1763
1764 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001765
Johan Hedbergb5235a62012-02-21 14:32:24 +02001766unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001767 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001768 return err;
1769}
1770
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001771static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001772 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001773{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001774 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001775 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001776 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001777
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001778 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001779
Johan Hedberg86742e12011-11-07 23:13:38 +02001780 expected_len = sizeof(*cp) + key_count *
1781 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001782 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001783 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001784 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001785 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001786 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001787 }
1788
Johan Hedberg4ae14302013-01-20 14:27:13 +02001789 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1790 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1791 MGMT_STATUS_INVALID_PARAMS);
1792
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001793 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001794 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001795
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001796 for (i = 0; i < key_count; i++) {
1797 struct mgmt_link_key_info *key = &cp->keys[i];
1798
1799 if (key->addr.type != BDADDR_BREDR)
1800 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1801 MGMT_STATUS_INVALID_PARAMS);
1802 }
1803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001804 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001805
1806 hci_link_keys_clear(hdev);
1807
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001808 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001809 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001810 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001811 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001812
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001813 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001814 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001815
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001816 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001817 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001818 }
1819
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001821
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001822 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001823
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001824 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001825}
1826
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001827static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001828 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001829{
1830 struct mgmt_ev_device_unpaired ev;
1831
1832 bacpy(&ev.addr.bdaddr, bdaddr);
1833 ev.addr.type = addr_type;
1834
1835 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001836 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001837}
1838
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001839static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001840 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001841{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001842 struct mgmt_cp_unpair_device *cp = data;
1843 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001844 struct hci_cp_disconnect dc;
1845 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001846 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001847 int err;
1848
Johan Hedberga8a1d192011-11-10 15:54:38 +02001849 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001850 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1851 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001852
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001853 if (!bdaddr_type_is_valid(cp->addr.type))
1854 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1855 MGMT_STATUS_INVALID_PARAMS,
1856 &rp, sizeof(rp));
1857
Johan Hedberg118da702013-01-20 14:27:20 +02001858 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1859 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1860 MGMT_STATUS_INVALID_PARAMS,
1861 &rp, sizeof(rp));
1862
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001863 hci_dev_lock(hdev);
1864
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001865 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001866 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001867 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001868 goto unlock;
1869 }
1870
Andre Guedes591f47f2012-04-24 21:02:49 -03001871 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001872 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1873 else
1874 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001875
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001876 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001877 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001878 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879 goto unlock;
1880 }
1881
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001882 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001883 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001884 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001885 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001886 else
1887 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001888 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001889 } else {
1890 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001891 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001892
Johan Hedberga8a1d192011-11-10 15:54:38 +02001893 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001894 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001895 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001896 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001897 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001898 }
1899
Johan Hedberg124f6e32012-02-09 13:50:12 +02001900 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001901 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001902 if (!cmd) {
1903 err = -ENOMEM;
1904 goto unlock;
1905 }
1906
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001907 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001908 dc.reason = 0x13; /* Remote User Terminated Connection */
1909 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1910 if (err < 0)
1911 mgmt_pending_remove(cmd);
1912
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001913unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001914 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001915 return err;
1916}
1917
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001918static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001919 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001920{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001921 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001922 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001923 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001924 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001925 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001926 int err;
1927
1928 BT_DBG("");
1929
Johan Hedberg06a63b12013-01-20 14:27:21 +02001930 memset(&rp, 0, sizeof(rp));
1931 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1932 rp.addr.type = cp->addr.type;
1933
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001934 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001935 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1936 MGMT_STATUS_INVALID_PARAMS,
1937 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001938
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001939 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001940
1941 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001942 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1943 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001944 goto failed;
1945 }
1946
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001947 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001948 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1949 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001950 goto failed;
1951 }
1952
Andre Guedes591f47f2012-04-24 21:02:49 -03001953 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001954 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1955 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001956 else
1957 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001958
Vishal Agarwalf9607272012-06-13 05:32:43 +05301959 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001960 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1961 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001962 goto failed;
1963 }
1964
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001965 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001966 if (!cmd) {
1967 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001968 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001969 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001970
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001971 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001972 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001973
1974 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1975 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001976 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001977
1978failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001979 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001980 return err;
1981}
1982
Andre Guedes57c14772012-04-24 21:02:50 -03001983static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001984{
1985 switch (link_type) {
1986 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001987 switch (addr_type) {
1988 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001989 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001990
Johan Hedberg48264f02011-11-09 13:58:58 +02001991 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001992 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001993 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001994 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001995
Johan Hedberg4c659c32011-11-07 23:13:39 +02001996 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001997 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001998 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001999 }
2000}
2001
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002002static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2003 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002004{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002005 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002006 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002007 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002008 int err;
2009 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002010
2011 BT_DBG("");
2012
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002013 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002014
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002015 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002016 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002017 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002018 goto unlock;
2019 }
2020
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002021 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002022 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2023 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002024 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002025 }
2026
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002027 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002028 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002029 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002030 err = -ENOMEM;
2031 goto unlock;
2032 }
2033
Johan Hedberg2784eb42011-01-21 13:56:35 +02002034 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002035 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002036 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2037 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002038 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002039 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002040 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002041 continue;
2042 i++;
2043 }
2044
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002045 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002046
Johan Hedberg4c659c32011-11-07 23:13:39 +02002047 /* Recalculate length in case of filtered SCO connections, etc */
2048 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002049
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002050 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002051 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002052
Johan Hedberga38528f2011-01-22 06:46:43 +02002053 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002054
2055unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002056 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002057 return err;
2058}
2059
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002060static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002061 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002062{
2063 struct pending_cmd *cmd;
2064 int err;
2065
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002066 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002067 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002068 if (!cmd)
2069 return -ENOMEM;
2070
Johan Hedbergd8457692012-02-17 14:24:57 +02002071 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002072 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002073 if (err < 0)
2074 mgmt_pending_remove(cmd);
2075
2076 return err;
2077}
2078
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002079static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002080 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002081{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002082 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002083 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002084 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002085 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002086 int err;
2087
2088 BT_DBG("");
2089
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002090 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002091
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002092 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002093 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002094 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002095 goto failed;
2096 }
2097
Johan Hedbergd8457692012-02-17 14:24:57 +02002098 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002099 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002100 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002101 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002102 goto failed;
2103 }
2104
2105 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002106 struct mgmt_cp_pin_code_neg_reply ncp;
2107
2108 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002109
2110 BT_ERR("PIN code is not 16 bytes long");
2111
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002112 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002113 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002116
2117 goto failed;
2118 }
2119
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002120 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002121 if (!cmd) {
2122 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002123 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002124 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002125
Johan Hedbergd8457692012-02-17 14:24:57 +02002126 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002127 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002128 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002129
2130 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2131 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002132 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002133
2134failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002135 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002136 return err;
2137}
2138
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002139static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2140 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002142 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002143
2144 BT_DBG("");
2145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002146 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002147
2148 hdev->io_capability = cp->io_capability;
2149
2150 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002151 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002153 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002154
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002155 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2156 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002157}
2158
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002159static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002160{
2161 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002162 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002164 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002165 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2166 continue;
2167
Johan Hedberge9a416b2011-02-19 12:05:56 -03002168 if (cmd->user_data != conn)
2169 continue;
2170
2171 return cmd;
2172 }
2173
2174 return NULL;
2175}
2176
2177static void pairing_complete(struct pending_cmd *cmd, u8 status)
2178{
2179 struct mgmt_rp_pair_device rp;
2180 struct hci_conn *conn = cmd->user_data;
2181
Johan Hedbergba4e5642011-11-11 00:07:34 +02002182 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002183 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002184
Johan Hedbergaee9b212012-02-18 15:07:59 +02002185 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002186 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002187
2188 /* So we don't get further callbacks for this connection */
2189 conn->connect_cfm_cb = NULL;
2190 conn->security_cfm_cb = NULL;
2191 conn->disconn_cfm_cb = NULL;
2192
David Herrmann76a68ba2013-04-06 20:28:37 +02002193 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002194
Johan Hedberga664b5b2011-02-19 12:06:02 -03002195 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002196}
2197
2198static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2199{
2200 struct pending_cmd *cmd;
2201
2202 BT_DBG("status %u", status);
2203
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002204 cmd = find_pairing(conn);
2205 if (!cmd)
2206 BT_DBG("Unable to find a pending command");
2207 else
Johan Hedberge2113262012-02-18 15:20:03 +02002208 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002209}
2210
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302211static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2212{
2213 struct pending_cmd *cmd;
2214
2215 BT_DBG("status %u", status);
2216
2217 if (!status)
2218 return;
2219
2220 cmd = find_pairing(conn);
2221 if (!cmd)
2222 BT_DBG("Unable to find a pending command");
2223 else
2224 pairing_complete(cmd, mgmt_status(status));
2225}
2226
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002227static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002228 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002229{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002230 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002231 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002232 struct pending_cmd *cmd;
2233 u8 sec_level, auth_type;
2234 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002235 int err;
2236
2237 BT_DBG("");
2238
Szymon Jancf950a30e2013-01-18 12:48:07 +01002239 memset(&rp, 0, sizeof(rp));
2240 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2241 rp.addr.type = cp->addr.type;
2242
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002243 if (!bdaddr_type_is_valid(cp->addr.type))
2244 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2245 MGMT_STATUS_INVALID_PARAMS,
2246 &rp, sizeof(rp));
2247
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002248 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002249
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002250 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002251 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2252 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002253 goto unlock;
2254 }
2255
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002256 sec_level = BT_SECURITY_MEDIUM;
2257 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002258 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002259 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002260 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002261
Andre Guedes591f47f2012-04-24 21:02:49 -03002262 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002263 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2264 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002265 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002266 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2267 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002268
Ville Tervo30e76272011-02-22 16:10:53 -03002269 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002270 int status;
2271
2272 if (PTR_ERR(conn) == -EBUSY)
2273 status = MGMT_STATUS_BUSY;
2274 else
2275 status = MGMT_STATUS_CONNECT_FAILED;
2276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002277 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002278 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002279 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002280 goto unlock;
2281 }
2282
2283 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002284 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002285 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002286 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002287 goto unlock;
2288 }
2289
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002290 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002291 if (!cmd) {
2292 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002293 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002294 goto unlock;
2295 }
2296
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002297 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002298 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002299 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302300 else
2301 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002302
Johan Hedberge9a416b2011-02-19 12:05:56 -03002303 conn->security_cfm_cb = pairing_complete_cb;
2304 conn->disconn_cfm_cb = pairing_complete_cb;
2305 conn->io_capability = cp->io_cap;
2306 cmd->user_data = conn;
2307
2308 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002309 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002310 pairing_complete(cmd, 0);
2311
2312 err = 0;
2313
2314unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002315 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002316 return err;
2317}
2318
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002319static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2320 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002321{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002322 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002323 struct pending_cmd *cmd;
2324 struct hci_conn *conn;
2325 int err;
2326
2327 BT_DBG("");
2328
Johan Hedberg28424702012-02-02 04:02:29 +02002329 hci_dev_lock(hdev);
2330
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002331 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002332 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002333 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002334 goto unlock;
2335 }
2336
Johan Hedberg28424702012-02-02 04:02:29 +02002337 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2338 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002339 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002341 goto unlock;
2342 }
2343
2344 conn = cmd->user_data;
2345
2346 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002347 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002348 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002349 goto unlock;
2350 }
2351
2352 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002354 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002355 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002356unlock:
2357 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002358 return err;
2359}
2360
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002361static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002362 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002363 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002364{
Johan Hedberga5c29682011-02-19 12:05:57 -03002365 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002366 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002367 int err;
2368
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002370
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002371 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002372 err = cmd_complete(sk, hdev->id, mgmt_op,
2373 MGMT_STATUS_NOT_POWERED, addr,
2374 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002375 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002376 }
2377
Johan Hedberg1707c602013-03-15 17:07:15 -05002378 if (addr->type == BDADDR_BREDR)
2379 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002380 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002381 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002382
Johan Hedberg272d90d2012-02-09 15:26:12 +02002383 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002384 err = cmd_complete(sk, hdev->id, mgmt_op,
2385 MGMT_STATUS_NOT_CONNECTED, addr,
2386 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002387 goto done;
2388 }
2389
Johan Hedberg1707c602013-03-15 17:07:15 -05002390 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002391 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002392 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002393
Brian Gix5fe57d92011-12-21 16:12:13 -08002394 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002395 err = cmd_complete(sk, hdev->id, mgmt_op,
2396 MGMT_STATUS_SUCCESS, addr,
2397 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002398 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002399 err = cmd_complete(sk, hdev->id, mgmt_op,
2400 MGMT_STATUS_FAILED, addr,
2401 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002402
Brian Gix47c15e22011-11-16 13:53:14 -08002403 goto done;
2404 }
2405
Johan Hedberg1707c602013-03-15 17:07:15 -05002406 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002407 if (!cmd) {
2408 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002409 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002410 }
2411
Brian Gix0df4c182011-11-16 13:53:13 -08002412 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002413 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2414 struct hci_cp_user_passkey_reply cp;
2415
Johan Hedberg1707c602013-03-15 17:07:15 -05002416 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002417 cp.passkey = passkey;
2418 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2419 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002420 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2421 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002422
Johan Hedberga664b5b2011-02-19 12:06:02 -03002423 if (err < 0)
2424 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002425
Brian Gix0df4c182011-11-16 13:53:13 -08002426done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002427 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002428 return err;
2429}
2430
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302431static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2432 void *data, u16 len)
2433{
2434 struct mgmt_cp_pin_code_neg_reply *cp = data;
2435
2436 BT_DBG("");
2437
Johan Hedberg1707c602013-03-15 17:07:15 -05002438 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302439 MGMT_OP_PIN_CODE_NEG_REPLY,
2440 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2441}
2442
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002443static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2444 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002445{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002446 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002447
2448 BT_DBG("");
2449
2450 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002451 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002452 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002453
Johan Hedberg1707c602013-03-15 17:07:15 -05002454 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 MGMT_OP_USER_CONFIRM_REPLY,
2456 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002457}
2458
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002459static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002460 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002461{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002462 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002463
2464 BT_DBG("");
2465
Johan Hedberg1707c602013-03-15 17:07:15 -05002466 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002467 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2468 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002469}
2470
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002471static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2472 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002473{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002474 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002475
2476 BT_DBG("");
2477
Johan Hedberg1707c602013-03-15 17:07:15 -05002478 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002479 MGMT_OP_USER_PASSKEY_REPLY,
2480 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002481}
2482
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002483static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002484 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002485{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002486 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002487
2488 BT_DBG("");
2489
Johan Hedberg1707c602013-03-15 17:07:15 -05002490 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002491 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2492 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002493}
2494
Johan Hedberg13928972013-03-15 17:07:00 -05002495static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002496{
Johan Hedberg13928972013-03-15 17:07:00 -05002497 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002498 struct hci_cp_write_local_name cp;
2499
Johan Hedberg13928972013-03-15 17:07:00 -05002500 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002501
Johan Hedberg890ea892013-03-15 17:06:52 -05002502 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002503}
2504
Johan Hedberg13928972013-03-15 17:07:00 -05002505static void set_name_complete(struct hci_dev *hdev, u8 status)
2506{
2507 struct mgmt_cp_set_local_name *cp;
2508 struct pending_cmd *cmd;
2509
2510 BT_DBG("status 0x%02x", status);
2511
2512 hci_dev_lock(hdev);
2513
2514 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2515 if (!cmd)
2516 goto unlock;
2517
2518 cp = cmd->param;
2519
2520 if (status)
2521 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2522 mgmt_status(status));
2523 else
2524 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2525 cp, sizeof(*cp));
2526
2527 mgmt_pending_remove(cmd);
2528
2529unlock:
2530 hci_dev_unlock(hdev);
2531}
2532
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002533static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002534 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002535{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002536 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002537 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002538 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002539 int err;
2540
2541 BT_DBG("");
2542
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002543 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002544
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002545 /* If the old values are the same as the new ones just return a
2546 * direct command complete event.
2547 */
2548 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2549 !memcmp(hdev->short_name, cp->short_name,
2550 sizeof(hdev->short_name))) {
2551 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2552 data, len);
2553 goto failed;
2554 }
2555
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002556 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002557
Johan Hedbergb5235a62012-02-21 14:32:24 +02002558 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002559 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002560
2561 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002562 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002563 if (err < 0)
2564 goto failed;
2565
2566 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002567 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002568
Johan Hedbergb5235a62012-02-21 14:32:24 +02002569 goto failed;
2570 }
2571
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002572 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002573 if (!cmd) {
2574 err = -ENOMEM;
2575 goto failed;
2576 }
2577
Johan Hedberg13928972013-03-15 17:07:00 -05002578 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2579
Johan Hedberg890ea892013-03-15 17:06:52 -05002580 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002581
2582 if (lmp_bredr_capable(hdev)) {
2583 update_name(&req);
2584 update_eir(&req);
2585 }
2586
2587 if (lmp_le_capable(hdev))
2588 hci_update_ad(&req);
2589
Johan Hedberg13928972013-03-15 17:07:00 -05002590 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002591 if (err < 0)
2592 mgmt_pending_remove(cmd);
2593
2594failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002595 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002596 return err;
2597}
2598
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002599static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002600 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002601{
Szymon Jancc35938b2011-03-22 13:12:21 +01002602 struct pending_cmd *cmd;
2603 int err;
2604
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002605 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002606
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002607 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002608
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002609 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002610 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002611 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002612 goto unlock;
2613 }
2614
Andre Guedes9a1a1992012-07-24 15:03:48 -03002615 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002616 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002617 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002618 goto unlock;
2619 }
2620
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002621 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002622 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002623 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002624 goto unlock;
2625 }
2626
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002627 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002628 if (!cmd) {
2629 err = -ENOMEM;
2630 goto unlock;
2631 }
2632
2633 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2634 if (err < 0)
2635 mgmt_pending_remove(cmd);
2636
2637unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002638 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002639 return err;
2640}
2641
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002642static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002643 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002644{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002645 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002646 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002647 int err;
2648
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002649 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002650
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002651 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002652
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002653 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002654 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002655 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002656 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002657 else
Szymon Janca6785be2012-12-13 15:11:21 +01002658 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002659
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002660 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002662
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002663 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002664 return err;
2665}
2666
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002667static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002668 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002669{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002670 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002671 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002672 int err;
2673
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002674 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002675
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002676 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002677
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002678 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002679 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002680 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002681 else
Szymon Janca6785be2012-12-13 15:11:21 +01002682 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002683
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002684 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002685 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002686
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002687 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002688 return err;
2689}
2690
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002691static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2692{
2693 struct pending_cmd *cmd;
2694 u8 type;
2695 int err;
2696
2697 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2698
2699 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2700 if (!cmd)
2701 return -ENOENT;
2702
2703 type = hdev->discovery.type;
2704
2705 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2706 &type, sizeof(type));
2707 mgmt_pending_remove(cmd);
2708
2709 return err;
2710}
2711
Andre Guedes7c307722013-04-30 15:29:28 -03002712static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2713{
2714 BT_DBG("status %d", status);
2715
2716 if (status) {
2717 hci_dev_lock(hdev);
2718 mgmt_start_discovery_failed(hdev, status);
2719 hci_dev_unlock(hdev);
2720 return;
2721 }
2722
2723 hci_dev_lock(hdev);
2724 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2725 hci_dev_unlock(hdev);
2726
2727 switch (hdev->discovery.type) {
2728 case DISCOV_TYPE_LE:
2729 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002730 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002731 break;
2732
2733 case DISCOV_TYPE_INTERLEAVED:
2734 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002735 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002736 break;
2737
2738 case DISCOV_TYPE_BREDR:
2739 break;
2740
2741 default:
2742 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2743 }
2744}
2745
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002746static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002748{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002749 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002750 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002751 struct hci_cp_le_set_scan_param param_cp;
2752 struct hci_cp_le_set_scan_enable enable_cp;
2753 struct hci_cp_inquiry inq_cp;
2754 struct hci_request req;
2755 /* General inquiry access code (GIAC) */
2756 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002757 int err;
2758
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002759 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002760
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002761 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002762
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002763 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002764 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002765 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002766 goto failed;
2767 }
2768
Andre Guedes642be6c2012-03-21 00:03:37 -03002769 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2770 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2771 MGMT_STATUS_BUSY);
2772 goto failed;
2773 }
2774
Johan Hedbergff9ef572012-01-04 14:23:45 +02002775 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002776 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002777 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002778 goto failed;
2779 }
2780
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002781 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002782 if (!cmd) {
2783 err = -ENOMEM;
2784 goto failed;
2785 }
2786
Andre Guedes4aab14e2012-02-17 20:39:36 -03002787 hdev->discovery.type = cp->type;
2788
Andre Guedes7c307722013-04-30 15:29:28 -03002789 hci_req_init(&req, hdev);
2790
Andre Guedes4aab14e2012-02-17 20:39:36 -03002791 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002792 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002793 if (!lmp_bredr_capable(hdev)) {
2794 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2795 MGMT_STATUS_NOT_SUPPORTED);
2796 mgmt_pending_remove(cmd);
2797 goto failed;
2798 }
2799
Andre Guedes7c307722013-04-30 15:29:28 -03002800 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2801 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2802 MGMT_STATUS_BUSY);
2803 mgmt_pending_remove(cmd);
2804 goto failed;
2805 }
2806
2807 hci_inquiry_cache_flush(hdev);
2808
2809 memset(&inq_cp, 0, sizeof(inq_cp));
2810 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002811 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002812 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002813 break;
2814
2815 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002816 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002817 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002818 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2819 MGMT_STATUS_NOT_SUPPORTED);
2820 mgmt_pending_remove(cmd);
2821 goto failed;
2822 }
2823
Andre Guedes7c307722013-04-30 15:29:28 -03002824 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
2825 !lmp_bredr_capable(hdev)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002826 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2827 MGMT_STATUS_NOT_SUPPORTED);
2828 mgmt_pending_remove(cmd);
2829 goto failed;
2830 }
2831
Andre Guedes7c307722013-04-30 15:29:28 -03002832 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2833 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2834 MGMT_STATUS_REJECTED);
2835 mgmt_pending_remove(cmd);
2836 goto failed;
2837 }
2838
2839 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2840 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2841 MGMT_STATUS_BUSY);
2842 mgmt_pending_remove(cmd);
2843 goto failed;
2844 }
2845
2846 memset(&param_cp, 0, sizeof(param_cp));
2847 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002848 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2849 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002850 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2851 &param_cp);
2852
2853 memset(&enable_cp, 0, sizeof(enable_cp));
2854 enable_cp.enable = LE_SCAN_ENABLE;
2855 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2856 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2857 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002858 break;
2859
Andre Guedesf39799f2012-02-17 20:39:35 -03002860 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002861 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2862 MGMT_STATUS_INVALID_PARAMS);
2863 mgmt_pending_remove(cmd);
2864 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002865 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002866
Andre Guedes7c307722013-04-30 15:29:28 -03002867 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002868 if (err < 0)
2869 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002870 else
2871 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002872
2873failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002874 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002875 return err;
2876}
2877
Andre Guedes1183fdc2013-04-30 15:29:35 -03002878static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2879{
2880 struct pending_cmd *cmd;
2881 int err;
2882
2883 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2884 if (!cmd)
2885 return -ENOENT;
2886
2887 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2888 &hdev->discovery.type, sizeof(hdev->discovery.type));
2889 mgmt_pending_remove(cmd);
2890
2891 return err;
2892}
2893
Andre Guedes0e05bba2013-04-30 15:29:33 -03002894static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2895{
2896 BT_DBG("status %d", status);
2897
2898 hci_dev_lock(hdev);
2899
2900 if (status) {
2901 mgmt_stop_discovery_failed(hdev, status);
2902 goto unlock;
2903 }
2904
2905 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2906
2907unlock:
2908 hci_dev_unlock(hdev);
2909}
2910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002911static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002912 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002913{
Johan Hedbergd9306502012-02-20 23:25:18 +02002914 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002915 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002916 struct hci_cp_remote_name_req_cancel cp;
2917 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002918 struct hci_request req;
2919 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002920 int err;
2921
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002922 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002923
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002924 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002925
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002926 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002927 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002928 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2929 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002930 goto unlock;
2931 }
2932
2933 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002934 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002935 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2936 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002937 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002938 }
2939
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002940 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002941 if (!cmd) {
2942 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002943 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002944 }
2945
Andre Guedes0e05bba2013-04-30 15:29:33 -03002946 hci_req_init(&req, hdev);
2947
Andre Guedese0d9727e2012-03-20 15:15:36 -03002948 switch (hdev->discovery.state) {
2949 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002950 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2951 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2952 } else {
2953 cancel_delayed_work(&hdev->le_scan_disable);
2954
2955 memset(&enable_cp, 0, sizeof(enable_cp));
2956 enable_cp.enable = LE_SCAN_DISABLE;
2957 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2958 sizeof(enable_cp), &enable_cp);
2959 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002960
Andre Guedese0d9727e2012-03-20 15:15:36 -03002961 break;
2962
2963 case DISCOVERY_RESOLVING:
2964 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002965 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002966 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002967 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002968 err = cmd_complete(sk, hdev->id,
2969 MGMT_OP_STOP_DISCOVERY, 0,
2970 &mgmt_cp->type,
2971 sizeof(mgmt_cp->type));
2972 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2973 goto unlock;
2974 }
2975
2976 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002977 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2978 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002979
2980 break;
2981
2982 default:
2983 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002984
2985 mgmt_pending_remove(cmd);
2986 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
2987 MGMT_STATUS_FAILED, &mgmt_cp->type,
2988 sizeof(mgmt_cp->type));
2989 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002990 }
2991
Andre Guedes0e05bba2013-04-30 15:29:33 -03002992 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002993 if (err < 0)
2994 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002995 else
2996 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002997
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002998unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002999 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003000 return err;
3001}
3002
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003003static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003004 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003005{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003006 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003007 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003008 int err;
3009
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003010 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003011
Johan Hedberg561aafb2012-01-04 13:31:59 +02003012 hci_dev_lock(hdev);
3013
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003014 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003015 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003016 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003017 goto failed;
3018 }
3019
Johan Hedberga198e7b2012-02-17 14:27:06 +02003020 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003021 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003022 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003024 goto failed;
3025 }
3026
3027 if (cp->name_known) {
3028 e->name_state = NAME_KNOWN;
3029 list_del(&e->list);
3030 } else {
3031 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003032 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003033 }
3034
Johan Hedberge3846622013-01-09 15:29:33 +02003035 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3036 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003037
3038failed:
3039 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003040 return err;
3041}
3042
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003043static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003044 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003045{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003046 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003047 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003048 int err;
3049
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003050 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003051
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003052 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003053 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3054 MGMT_STATUS_INVALID_PARAMS,
3055 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003056
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003057 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003058
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003059 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003060 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003061 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003062 else
Szymon Janca6785be2012-12-13 15:11:21 +01003063 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003064
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003065 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003066 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003067
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003068 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003069
3070 return err;
3071}
3072
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003073static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003074 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003075{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003076 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003077 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003078 int err;
3079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003080 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003081
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003082 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003083 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3084 MGMT_STATUS_INVALID_PARAMS,
3085 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003086
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003087 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003088
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003089 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003090 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003091 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003092 else
Szymon Janca6785be2012-12-13 15:11:21 +01003093 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003094
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003095 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003096 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003097
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003098 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003099
3100 return err;
3101}
3102
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003103static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3104 u16 len)
3105{
3106 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003107 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003108 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003109 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003110
3111 BT_DBG("%s", hdev->name);
3112
Szymon Jancc72d4b82012-03-16 16:02:57 +01003113 source = __le16_to_cpu(cp->source);
3114
3115 if (source > 0x0002)
3116 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3117 MGMT_STATUS_INVALID_PARAMS);
3118
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003119 hci_dev_lock(hdev);
3120
Szymon Jancc72d4b82012-03-16 16:02:57 +01003121 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003122 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3123 hdev->devid_product = __le16_to_cpu(cp->product);
3124 hdev->devid_version = __le16_to_cpu(cp->version);
3125
3126 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3127
Johan Hedberg890ea892013-03-15 17:06:52 -05003128 hci_req_init(&req, hdev);
3129 update_eir(&req);
3130 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003131
3132 hci_dev_unlock(hdev);
3133
3134 return err;
3135}
3136
Johan Hedberg4375f102013-09-25 13:26:10 +03003137static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3138{
3139 struct cmd_lookup match = { NULL, hdev };
3140
3141 if (status) {
3142 u8 mgmt_err = mgmt_status(status);
3143
3144 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3145 cmd_status_rsp, &mgmt_err);
3146 return;
3147 }
3148
3149 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3150 &match);
3151
3152 new_settings(hdev, match.sk);
3153
3154 if (match.sk)
3155 sock_put(match.sk);
3156}
3157
3158static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3159{
3160 struct mgmt_mode *cp = data;
3161 struct pending_cmd *cmd;
3162 struct hci_request req;
3163 u8 val, enabled;
3164 int err;
3165
3166 BT_DBG("request for %s", hdev->name);
3167
3168 if (!lmp_le_capable(hdev))
3169 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3170 MGMT_STATUS_NOT_SUPPORTED);
3171
3172 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3173 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3174 MGMT_STATUS_REJECTED);
3175
3176 if (cp->val != 0x00 && cp->val != 0x01)
3177 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3178 MGMT_STATUS_INVALID_PARAMS);
3179
3180 hci_dev_lock(hdev);
3181
3182 val = !!cp->val;
3183 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3184
3185 if (!hdev_is_powered(hdev) || val == enabled) {
3186 bool changed = false;
3187
3188 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3189 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3190 changed = true;
3191 }
3192
3193 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3194 if (err < 0)
3195 goto unlock;
3196
3197 if (changed)
3198 err = new_settings(hdev, sk);
3199
3200 goto unlock;
3201 }
3202
3203 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3204 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3205 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3206 MGMT_STATUS_BUSY);
3207 goto unlock;
3208 }
3209
3210 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3211 if (!cmd) {
3212 err = -ENOMEM;
3213 goto unlock;
3214 }
3215
3216 hci_req_init(&req, hdev);
3217
3218 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3219
3220 err = hci_req_run(&req, set_advertising_complete);
3221 if (err < 0)
3222 mgmt_pending_remove(cmd);
3223
3224unlock:
3225 hci_dev_unlock(hdev);
3226 return err;
3227}
3228
Johan Hedberg33e38b32013-03-15 17:07:05 -05003229static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3230{
3231 struct pending_cmd *cmd;
3232
3233 BT_DBG("status 0x%02x", status);
3234
3235 hci_dev_lock(hdev);
3236
3237 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3238 if (!cmd)
3239 goto unlock;
3240
3241 if (status) {
3242 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3243 mgmt_status(status));
3244 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003245 struct mgmt_mode *cp = cmd->param;
3246
3247 if (cp->val)
3248 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3249 else
3250 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3251
Johan Hedberg33e38b32013-03-15 17:07:05 -05003252 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3253 new_settings(hdev, cmd->sk);
3254 }
3255
3256 mgmt_pending_remove(cmd);
3257
3258unlock:
3259 hci_dev_unlock(hdev);
3260}
3261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003262static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003263 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003264{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003265 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003266 struct pending_cmd *cmd;
3267 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003268 int err;
3269
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003270 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003271
Johan Hedberg1a47aee2013-03-15 17:07:06 -05003272 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003273 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3274 MGMT_STATUS_NOT_SUPPORTED);
3275
Johan Hedberga7e80f22013-01-09 16:05:19 +02003276 if (cp->val != 0x00 && cp->val != 0x01)
3277 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3278 MGMT_STATUS_INVALID_PARAMS);
3279
Johan Hedberg5400c042012-02-21 16:40:33 +02003280 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003281 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003282 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003283
3284 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003285 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003286 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003287
3288 hci_dev_lock(hdev);
3289
Johan Hedberg05cbf292013-03-15 17:07:07 -05003290 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3291 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3292 MGMT_STATUS_BUSY);
3293 goto unlock;
3294 }
3295
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003296 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3297 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3298 hdev);
3299 goto unlock;
3300 }
3301
Johan Hedberg33e38b32013-03-15 17:07:05 -05003302 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3303 data, len);
3304 if (!cmd) {
3305 err = -ENOMEM;
3306 goto unlock;
3307 }
3308
3309 hci_req_init(&req, hdev);
3310
Johan Hedberg406d7802013-03-15 17:07:09 -05003311 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003312
3313 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003314 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003315 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003316 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003317 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003318 }
3319
Johan Hedberg33e38b32013-03-15 17:07:05 -05003320unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003321 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003322
Antti Julkuf6422ec2011-06-22 13:11:56 +03003323 return err;
3324}
3325
Johan Hedberg3f706b72013-01-20 14:27:16 +02003326static bool ltk_is_valid(struct mgmt_ltk_info *key)
3327{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003328 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3329 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003330 if (key->master != 0x00 && key->master != 0x01)
3331 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003332 if (!bdaddr_type_is_le(key->addr.type))
3333 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003334 return true;
3335}
3336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003337static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003338 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003339{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003340 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3341 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003342 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003343
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003344 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003345
3346 expected_len = sizeof(*cp) + key_count *
3347 sizeof(struct mgmt_ltk_info);
3348 if (expected_len != len) {
3349 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003350 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003351 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003352 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003353 }
3354
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003355 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003356
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003357 for (i = 0; i < key_count; i++) {
3358 struct mgmt_ltk_info *key = &cp->keys[i];
3359
Johan Hedberg3f706b72013-01-20 14:27:16 +02003360 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003361 return cmd_status(sk, hdev->id,
3362 MGMT_OP_LOAD_LONG_TERM_KEYS,
3363 MGMT_STATUS_INVALID_PARAMS);
3364 }
3365
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003366 hci_dev_lock(hdev);
3367
3368 hci_smp_ltks_clear(hdev);
3369
3370 for (i = 0; i < key_count; i++) {
3371 struct mgmt_ltk_info *key = &cp->keys[i];
3372 u8 type;
3373
3374 if (key->master)
3375 type = HCI_SMP_LTK;
3376 else
3377 type = HCI_SMP_LTK_SLAVE;
3378
Hemant Gupta4596fde2012-04-16 14:57:40 +05303379 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003380 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003381 type, 0, key->authenticated, key->val,
3382 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003383 }
3384
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003385 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3386 NULL, 0);
3387
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003388 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003389
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003390 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003391}
3392
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003393static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003394 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3395 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003396 bool var_len;
3397 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003398} mgmt_handlers[] = {
3399 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003400 { read_version, false, MGMT_READ_VERSION_SIZE },
3401 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3402 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3403 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3404 { set_powered, false, MGMT_SETTING_SIZE },
3405 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3406 { set_connectable, false, MGMT_SETTING_SIZE },
3407 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3408 { set_pairable, false, MGMT_SETTING_SIZE },
3409 { set_link_security, false, MGMT_SETTING_SIZE },
3410 { set_ssp, false, MGMT_SETTING_SIZE },
3411 { set_hs, false, MGMT_SETTING_SIZE },
3412 { set_le, false, MGMT_SETTING_SIZE },
3413 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3414 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3415 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3416 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3417 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3418 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3419 { disconnect, false, MGMT_DISCONNECT_SIZE },
3420 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3421 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3422 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3423 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3424 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3425 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3426 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3427 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3428 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3429 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3430 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3431 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3432 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3433 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3434 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3435 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3436 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3437 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3438 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003439 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003440 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003441};
3442
3443
Johan Hedberg03811012010-12-08 00:21:06 +02003444int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3445{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003446 void *buf;
3447 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003448 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003449 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003450 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003451 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003452 int err;
3453
3454 BT_DBG("got %zu bytes", msglen);
3455
3456 if (msglen < sizeof(*hdr))
3457 return -EINVAL;
3458
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003459 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003460 if (!buf)
3461 return -ENOMEM;
3462
3463 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3464 err = -EFAULT;
3465 goto done;
3466 }
3467
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003468 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003469 opcode = __le16_to_cpu(hdr->opcode);
3470 index = __le16_to_cpu(hdr->index);
3471 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003472
3473 if (len != msglen - sizeof(*hdr)) {
3474 err = -EINVAL;
3475 goto done;
3476 }
3477
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003478 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003479 hdev = hci_dev_get(index);
3480 if (!hdev) {
3481 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003482 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003483 goto done;
3484 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003485
3486 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3487 err = cmd_status(sk, index, opcode,
3488 MGMT_STATUS_INVALID_INDEX);
3489 goto done;
3490 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003491 }
3492
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003493 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003494 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003495 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003496 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003497 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003498 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003499 }
3500
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003501 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003502 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003503 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003504 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003505 goto done;
3506 }
3507
Johan Hedbergbe22b542012-03-01 22:24:41 +02003508 handler = &mgmt_handlers[opcode];
3509
3510 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003511 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003512 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003513 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003514 goto done;
3515 }
3516
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003517 if (hdev)
3518 mgmt_init_hdev(sk, hdev);
3519
3520 cp = buf + sizeof(*hdr);
3521
Johan Hedbergbe22b542012-03-01 22:24:41 +02003522 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003523 if (err < 0)
3524 goto done;
3525
Johan Hedberg03811012010-12-08 00:21:06 +02003526 err = msglen;
3527
3528done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003529 if (hdev)
3530 hci_dev_put(hdev);
3531
Johan Hedberg03811012010-12-08 00:21:06 +02003532 kfree(buf);
3533 return err;
3534}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003535
Johan Hedberg744cf192011-11-08 20:40:14 +02003536int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003537{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003538 if (!mgmt_valid_hdev(hdev))
3539 return -ENOTSUPP;
3540
Johan Hedberg744cf192011-11-08 20:40:14 +02003541 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003542}
3543
Johan Hedberg744cf192011-11-08 20:40:14 +02003544int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003545{
Johan Hedberg5f159032012-03-02 03:13:19 +02003546 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003547
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003548 if (!mgmt_valid_hdev(hdev))
3549 return -ENOTSUPP;
3550
Johan Hedberg744cf192011-11-08 20:40:14 +02003551 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003552
Johan Hedberg744cf192011-11-08 20:40:14 +02003553 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003554}
3555
Johan Hedberg890ea892013-03-15 17:06:52 -05003556static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003557{
Johan Hedberg890ea892013-03-15 17:06:52 -05003558 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003559 u8 scan = 0;
3560
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003561 /* Ensure that fast connectable is disabled. This function will
3562 * not do anything if the page scan parameters are already what
3563 * they should be.
3564 */
3565 write_fast_connectable(req, false);
3566
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003567 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3568 scan |= SCAN_PAGE;
3569 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3570 scan |= SCAN_INQUIRY;
3571
Johan Hedberg890ea892013-03-15 17:06:52 -05003572 if (scan)
3573 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003574}
3575
Johan Hedberg229ab392013-03-15 17:06:53 -05003576static void powered_complete(struct hci_dev *hdev, u8 status)
3577{
3578 struct cmd_lookup match = { NULL, hdev };
3579
3580 BT_DBG("status 0x%02x", status);
3581
3582 hci_dev_lock(hdev);
3583
3584 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3585
3586 new_settings(hdev, match.sk);
3587
3588 hci_dev_unlock(hdev);
3589
3590 if (match.sk)
3591 sock_put(match.sk);
3592}
3593
Johan Hedberg70da6242013-03-15 17:06:51 -05003594static int powered_update_hci(struct hci_dev *hdev)
3595{
Johan Hedberg890ea892013-03-15 17:06:52 -05003596 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003597 u8 link_sec;
3598
Johan Hedberg890ea892013-03-15 17:06:52 -05003599 hci_req_init(&req, hdev);
3600
Johan Hedberg70da6242013-03-15 17:06:51 -05003601 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3602 !lmp_host_ssp_capable(hdev)) {
3603 u8 ssp = 1;
3604
Johan Hedberg890ea892013-03-15 17:06:52 -05003605 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003606 }
3607
Johan Hedbergc73eee92013-04-19 18:35:21 +03003608 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3609 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003610 struct hci_cp_write_le_host_supported cp;
3611
3612 cp.le = 1;
3613 cp.simul = lmp_le_br_capable(hdev);
3614
3615 /* Check first if we already have the right
3616 * host state (host features set)
3617 */
3618 if (cp.le != lmp_host_le_capable(hdev) ||
3619 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003620 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3621 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003622 }
3623
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003624 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3625 u8 adv = 0x01;
3626
3627 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3628 }
3629
Johan Hedberg70da6242013-03-15 17:06:51 -05003630 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3631 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003632 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3633 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003634
3635 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003636 set_bredr_scan(&req);
3637 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003638 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003639 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003640 }
3641
Johan Hedberg229ab392013-03-15 17:06:53 -05003642 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003643}
3644
Johan Hedberg744cf192011-11-08 20:40:14 +02003645int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003646{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003647 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003648 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3649 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003650 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003651
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003652 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3653 return 0;
3654
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003655 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003656 if (powered_update_hci(hdev) == 0)
3657 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003658
Johan Hedberg229ab392013-03-15 17:06:53 -05003659 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3660 &match);
3661 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003662 }
3663
Johan Hedberg229ab392013-03-15 17:06:53 -05003664 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3665 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3666
3667 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3668 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3669 zero_cod, sizeof(zero_cod), NULL);
3670
3671new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003672 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003673
3674 if (match.sk)
3675 sock_put(match.sk);
3676
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003677 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003678}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003679
Johan Hedberg96570ff2013-05-29 09:51:29 +03003680int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3681{
3682 struct pending_cmd *cmd;
3683 u8 status;
3684
3685 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3686 if (!cmd)
3687 return -ENOENT;
3688
3689 if (err == -ERFKILL)
3690 status = MGMT_STATUS_RFKILLED;
3691 else
3692 status = MGMT_STATUS_FAILED;
3693
3694 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3695
3696 mgmt_pending_remove(cmd);
3697
3698 return err;
3699}
3700
Johan Hedberg744cf192011-11-08 20:40:14 +02003701int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003702{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003703 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003704 bool changed = false;
3705 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003706
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003707 if (discoverable) {
3708 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3709 changed = true;
3710 } else {
3711 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3712 changed = true;
3713 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003714
Johan Hedberged9b5f22012-02-21 20:47:06 +02003715 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003716 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003717
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003718 if (changed)
3719 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003720
Johan Hedberg73f22f62010-12-29 16:00:25 +02003721 if (match.sk)
3722 sock_put(match.sk);
3723
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003724 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003725}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003726
Johan Hedberg744cf192011-11-08 20:40:14 +02003727int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003728{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003729 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003730 bool changed = false;
3731 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003732
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003733 if (connectable) {
3734 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3735 changed = true;
3736 } else {
3737 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3738 changed = true;
3739 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003740
Johan Hedberg2b76f452013-03-15 17:07:04 -05003741 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003742
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003743 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003744 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003745
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003746 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003747}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003748
Johan Hedberg744cf192011-11-08 20:40:14 +02003749int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003750{
Johan Hedbergca69b792011-11-11 18:10:00 +02003751 u8 mgmt_err = mgmt_status(status);
3752
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003753 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003754 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003755 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003756
3757 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003758 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003759 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003760
3761 return 0;
3762}
3763
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003764int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3765 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003766{
Johan Hedberg86742e12011-11-07 23:13:38 +02003767 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003768
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003769 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003770
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003771 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003772 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003773 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003774 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003775 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003776 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003777
Johan Hedberg744cf192011-11-08 20:40:14 +02003778 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003779}
Johan Hedbergf7520542011-01-20 12:34:39 +02003780
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003781int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3782{
3783 struct mgmt_ev_new_long_term_key ev;
3784
3785 memset(&ev, 0, sizeof(ev));
3786
3787 ev.store_hint = persistent;
3788 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003789 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003790 ev.key.authenticated = key->authenticated;
3791 ev.key.enc_size = key->enc_size;
3792 ev.key.ediv = key->ediv;
3793
3794 if (key->type == HCI_SMP_LTK)
3795 ev.key.master = 1;
3796
3797 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3798 memcpy(ev.key.val, key->val, sizeof(key->val));
3799
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003800 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3801 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003802}
3803
Johan Hedbergafc747a2012-01-15 18:11:07 +02003804int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003805 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3806 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003807{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003808 char buf[512];
3809 struct mgmt_ev_device_connected *ev = (void *) buf;
3810 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003811
Johan Hedbergb644ba32012-01-17 21:48:47 +02003812 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003813 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003814
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003815 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003816
Johan Hedbergb644ba32012-01-17 21:48:47 +02003817 if (name_len > 0)
3818 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003819 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003820
3821 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003822 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003823 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003824
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003825 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003826
3827 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003828 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003829}
3830
Johan Hedberg8962ee72011-01-20 12:40:27 +02003831static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3832{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003833 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003834 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003835 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003836
Johan Hedberg88c3df12012-02-09 14:27:38 +02003837 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3838 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003839
Johan Hedbergaee9b212012-02-18 15:07:59 +02003840 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003841 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003842
3843 *sk = cmd->sk;
3844 sock_hold(*sk);
3845
Johan Hedberga664b5b2011-02-19 12:06:02 -03003846 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003847}
3848
Johan Hedberg124f6e32012-02-09 13:50:12 +02003849static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003850{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003851 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003852 struct mgmt_cp_unpair_device *cp = cmd->param;
3853 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003854
3855 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003856 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3857 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003858
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003859 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3860
Johan Hedbergaee9b212012-02-18 15:07:59 +02003861 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003862
3863 mgmt_pending_remove(cmd);
3864}
3865
Johan Hedbergafc747a2012-01-15 18:11:07 +02003866int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003867 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003868{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003869 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003870 struct sock *sk = NULL;
3871 int err;
3872
Johan Hedberg744cf192011-11-08 20:40:14 +02003873 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003874
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003875 bacpy(&ev.addr.bdaddr, bdaddr);
3876 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3877 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003878
Johan Hedbergafc747a2012-01-15 18:11:07 +02003879 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003880 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003881
3882 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003883 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003884
Johan Hedberg124f6e32012-02-09 13:50:12 +02003885 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003886 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003887
Johan Hedberg8962ee72011-01-20 12:40:27 +02003888 return err;
3889}
3890
Johan Hedberg88c3df12012-02-09 14:27:38 +02003891int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003892 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003893{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003894 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003895 struct pending_cmd *cmd;
3896 int err;
3897
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003898 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3899 hdev);
3900
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003901 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003902 if (!cmd)
3903 return -ENOENT;
3904
Johan Hedberg88c3df12012-02-09 14:27:38 +02003905 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003906 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003907
Johan Hedberg88c3df12012-02-09 14:27:38 +02003908 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003909 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003910
Johan Hedberga664b5b2011-02-19 12:06:02 -03003911 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003912
3913 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003914}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003915
Johan Hedberg48264f02011-11-09 13:58:58 +02003916int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003917 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003918{
3919 struct mgmt_ev_connect_failed ev;
3920
Johan Hedberg4c659c32011-11-07 23:13:39 +02003921 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003922 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003923 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003924
Johan Hedberg744cf192011-11-08 20:40:14 +02003925 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003926}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003927
Johan Hedberg744cf192011-11-08 20:40:14 +02003928int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003929{
3930 struct mgmt_ev_pin_code_request ev;
3931
Johan Hedbergd8457692012-02-17 14:24:57 +02003932 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003933 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003934 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003935
Johan Hedberg744cf192011-11-08 20:40:14 +02003936 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003937 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003938}
3939
Johan Hedberg744cf192011-11-08 20:40:14 +02003940int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003941 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003942{
3943 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003944 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003945 int err;
3946
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003947 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003948 if (!cmd)
3949 return -ENOENT;
3950
Johan Hedbergd8457692012-02-17 14:24:57 +02003951 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003952 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003953
Johan Hedbergaee9b212012-02-18 15:07:59 +02003954 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003955 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003956
Johan Hedberga664b5b2011-02-19 12:06:02 -03003957 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003958
3959 return err;
3960}
3961
Johan Hedberg744cf192011-11-08 20:40:14 +02003962int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003963 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003964{
3965 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003966 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003967 int err;
3968
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003969 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003970 if (!cmd)
3971 return -ENOENT;
3972
Johan Hedbergd8457692012-02-17 14:24:57 +02003973 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003974 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003975
Johan Hedbergaee9b212012-02-18 15:07:59 +02003976 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003977 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003978
Johan Hedberga664b5b2011-02-19 12:06:02 -03003979 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003980
3981 return err;
3982}
Johan Hedberga5c29682011-02-19 12:05:57 -03003983
Johan Hedberg744cf192011-11-08 20:40:14 +02003984int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003985 u8 link_type, u8 addr_type, __le32 value,
3986 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003987{
3988 struct mgmt_ev_user_confirm_request ev;
3989
Johan Hedberg744cf192011-11-08 20:40:14 +02003990 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003991
Johan Hedberg272d90d2012-02-09 15:26:12 +02003992 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003993 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003994 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003995 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003996
Johan Hedberg744cf192011-11-08 20:40:14 +02003997 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003998 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003999}
4000
Johan Hedberg272d90d2012-02-09 15:26:12 +02004001int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004002 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004003{
4004 struct mgmt_ev_user_passkey_request ev;
4005
4006 BT_DBG("%s", hdev->name);
4007
Johan Hedberg272d90d2012-02-09 15:26:12 +02004008 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004009 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004010
4011 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004012 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004013}
4014
Brian Gix0df4c182011-11-16 13:53:13 -08004015static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004016 u8 link_type, u8 addr_type, u8 status,
4017 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004018{
4019 struct pending_cmd *cmd;
4020 struct mgmt_rp_user_confirm_reply rp;
4021 int err;
4022
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004023 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004024 if (!cmd)
4025 return -ENOENT;
4026
Johan Hedberg272d90d2012-02-09 15:26:12 +02004027 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004028 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004029 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004030 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004031
Johan Hedberga664b5b2011-02-19 12:06:02 -03004032 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004033
4034 return err;
4035}
4036
Johan Hedberg744cf192011-11-08 20:40:14 +02004037int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004038 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004039{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004040 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004041 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004042}
4043
Johan Hedberg272d90d2012-02-09 15:26:12 +02004044int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004045 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004046{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004047 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004048 status,
4049 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004050}
Johan Hedberg2a611692011-02-19 12:06:00 -03004051
Brian Gix604086b2011-11-23 08:28:33 -08004052int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004053 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004054{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004055 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004056 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004057}
4058
Johan Hedberg272d90d2012-02-09 15:26:12 +02004059int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004060 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004061{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004062 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004063 status,
4064 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004065}
4066
Johan Hedberg92a25252012-09-06 18:39:26 +03004067int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4068 u8 link_type, u8 addr_type, u32 passkey,
4069 u8 entered)
4070{
4071 struct mgmt_ev_passkey_notify ev;
4072
4073 BT_DBG("%s", hdev->name);
4074
4075 bacpy(&ev.addr.bdaddr, bdaddr);
4076 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4077 ev.passkey = __cpu_to_le32(passkey);
4078 ev.entered = entered;
4079
4080 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4081}
4082
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004083int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004084 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004085{
4086 struct mgmt_ev_auth_failed ev;
4087
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004088 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004089 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004090 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004091
Johan Hedberg744cf192011-11-08 20:40:14 +02004092 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004093}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004094
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004095int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4096{
4097 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004098 bool changed = false;
4099 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004100
4101 if (status) {
4102 u8 mgmt_err = mgmt_status(status);
4103 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004104 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004105 return 0;
4106 }
4107
Johan Hedberg47990ea2012-02-22 11:58:37 +02004108 if (test_bit(HCI_AUTH, &hdev->flags)) {
4109 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4110 changed = true;
4111 } else {
4112 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4113 changed = true;
4114 }
4115
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004116 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004117 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004118
Johan Hedberg47990ea2012-02-22 11:58:37 +02004119 if (changed)
4120 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004121
4122 if (match.sk)
4123 sock_put(match.sk);
4124
4125 return err;
4126}
4127
Johan Hedberg890ea892013-03-15 17:06:52 -05004128static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004129{
Johan Hedberg890ea892013-03-15 17:06:52 -05004130 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004131 struct hci_cp_write_eir cp;
4132
Johan Hedberg976eb202012-10-24 21:12:01 +03004133 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004134 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004135
Johan Hedbergc80da272012-02-22 15:38:48 +02004136 memset(hdev->eir, 0, sizeof(hdev->eir));
4137
Johan Hedbergcacaf522012-02-21 00:52:42 +02004138 memset(&cp, 0, sizeof(cp));
4139
Johan Hedberg890ea892013-03-15 17:06:52 -05004140 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004141}
4142
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004143int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004144{
4145 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004146 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004147 bool changed = false;
4148 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004149
4150 if (status) {
4151 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004152
4153 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004154 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004155 err = new_settings(hdev, NULL);
4156
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004157 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4158 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004159
4160 return err;
4161 }
4162
4163 if (enable) {
4164 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4165 changed = true;
4166 } else {
4167 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4168 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004169 }
4170
4171 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4172
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004173 if (changed)
4174 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004175
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004176 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004177 sock_put(match.sk);
4178
Johan Hedberg890ea892013-03-15 17:06:52 -05004179 hci_req_init(&req, hdev);
4180
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004181 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004182 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004183 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004184 clear_eir(&req);
4185
4186 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004187
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004188 return err;
4189}
4190
Johan Hedberg92da6092013-03-15 17:06:55 -05004191static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004192{
4193 struct cmd_lookup *match = data;
4194
Johan Hedberg90e70452012-02-23 23:09:40 +02004195 if (match->sk == NULL) {
4196 match->sk = cmd->sk;
4197 sock_hold(match->sk);
4198 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004199}
4200
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004201int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004202 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004203{
Johan Hedberg90e70452012-02-23 23:09:40 +02004204 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4205 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004206
Johan Hedberg92da6092013-03-15 17:06:55 -05004207 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4208 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4209 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004210
4211 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004212 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4213 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004214
4215 if (match.sk)
4216 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004217
4218 return err;
4219}
4220
Johan Hedberg744cf192011-11-08 20:40:14 +02004221int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004222{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004223 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004224 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004225
Johan Hedberg13928972013-03-15 17:07:00 -05004226 if (status)
4227 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004228
4229 memset(&ev, 0, sizeof(ev));
4230 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004231 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004232
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004233 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004234 if (!cmd) {
4235 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004236
Johan Hedberg13928972013-03-15 17:07:00 -05004237 /* If this is a HCI command related to powering on the
4238 * HCI dev don't send any mgmt signals.
4239 */
4240 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4241 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004242 }
4243
Johan Hedberg13928972013-03-15 17:07:00 -05004244 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4245 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004246}
Szymon Jancc35938b2011-03-22 13:12:21 +01004247
Johan Hedberg744cf192011-11-08 20:40:14 +02004248int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004249 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004250{
4251 struct pending_cmd *cmd;
4252 int err;
4253
Johan Hedberg744cf192011-11-08 20:40:14 +02004254 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004255
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004256 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004257 if (!cmd)
4258 return -ENOENT;
4259
4260 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004261 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4262 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004263 } else {
4264 struct mgmt_rp_read_local_oob_data rp;
4265
4266 memcpy(rp.hash, hash, sizeof(rp.hash));
4267 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4268
Johan Hedberg744cf192011-11-08 20:40:14 +02004269 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004270 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4271 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004272 }
4273
4274 mgmt_pending_remove(cmd);
4275
4276 return err;
4277}
Johan Hedberge17acd42011-03-30 23:57:16 +03004278
Johan Hedberg48264f02011-11-09 13:58:58 +02004279int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004280 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4281 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004282{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004283 char buf[512];
4284 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004285 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004286
Andre Guedes12602d02013-04-30 15:29:40 -03004287 if (!hci_discovery_active(hdev))
4288 return -EPERM;
4289
Johan Hedberg1dc06092012-01-15 21:01:23 +02004290 /* Leave 5 bytes for a potential CoD field */
4291 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004292 return -EINVAL;
4293
Johan Hedberg1dc06092012-01-15 21:01:23 +02004294 memset(buf, 0, sizeof(buf));
4295
Johan Hedberge319d2e2012-01-15 19:51:59 +02004296 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004297 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004298 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004299 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304300 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004301 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304302 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004303
Johan Hedberg1dc06092012-01-15 21:01:23 +02004304 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004305 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004306
Johan Hedberg1dc06092012-01-15 21:01:23 +02004307 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4308 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004309 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004310
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004311 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004312 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004313
Johan Hedberge319d2e2012-01-15 19:51:59 +02004314 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004315}
Johan Hedberga88a9652011-03-30 13:18:12 +03004316
Johan Hedbergb644ba32012-01-17 21:48:47 +02004317int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004318 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004319{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004320 struct mgmt_ev_device_found *ev;
4321 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4322 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004323
Johan Hedbergb644ba32012-01-17 21:48:47 +02004324 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004325
Johan Hedbergb644ba32012-01-17 21:48:47 +02004326 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004327
Johan Hedbergb644ba32012-01-17 21:48:47 +02004328 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004329 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004330 ev->rssi = rssi;
4331
4332 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004333 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004334
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004335 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004336
Johan Hedberg053c7e02012-02-04 00:06:00 +02004337 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004338 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004339}
Johan Hedberg314b2382011-04-27 10:29:57 -04004340
Johan Hedberg744cf192011-11-08 20:40:14 +02004341int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004342{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004343 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004344 struct pending_cmd *cmd;
4345
Andre Guedes343fb142011-11-22 17:14:19 -03004346 BT_DBG("%s discovering %u", hdev->name, discovering);
4347
Johan Hedberg164a6e72011-11-01 17:06:44 +02004348 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004349 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004350 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004351 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004352
4353 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004354 u8 type = hdev->discovery.type;
4355
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004356 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4357 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004358 mgmt_pending_remove(cmd);
4359 }
4360
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004361 memset(&ev, 0, sizeof(ev));
4362 ev.type = hdev->discovery.type;
4363 ev.discovering = discovering;
4364
4365 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004366}
Antti Julku5e762442011-08-25 16:48:02 +03004367
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004368int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004369{
4370 struct pending_cmd *cmd;
4371 struct mgmt_ev_device_blocked ev;
4372
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004373 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004374
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004375 bacpy(&ev.addr.bdaddr, bdaddr);
4376 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004377
Johan Hedberg744cf192011-11-08 20:40:14 +02004378 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004379 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004380}
4381
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004382int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004383{
4384 struct pending_cmd *cmd;
4385 struct mgmt_ev_device_unblocked ev;
4386
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004387 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004388
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004389 bacpy(&ev.addr.bdaddr, bdaddr);
4390 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004391
Johan Hedberg744cf192011-11-08 20:40:14 +02004392 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004393 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004394}