blob: e1c41b0b7a754fbe96656378d1905e9b431bc554 [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
Johan Hedberg56f87902013-10-02 13:43:13 +0300411 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
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 Hedberg56f87902013-10-02 13:43:13 +0300932 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +0300933 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 Hedberg56f87902013-10-02 13:43:13 +03001088 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001089 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 Hedberg56f87902013-10-02 13:43:13 +03001211 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001212 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1213 MGMT_STATUS_NOT_SUPPORTED);
1214
Johan Hedberga7e80f22013-01-09 16:05:19 +02001215 if (cp->val != 0x00 && cp->val != 0x01)
1216 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1217 MGMT_STATUS_INVALID_PARAMS);
1218
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001219 hci_dev_lock(hdev);
1220
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001221 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001222 bool changed = false;
1223
1224 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001225 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001226 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1227 changed = true;
1228 }
1229
1230 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1231 if (err < 0)
1232 goto failed;
1233
1234 if (changed)
1235 err = new_settings(hdev, sk);
1236
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001237 goto failed;
1238 }
1239
1240 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001241 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001242 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001243 goto failed;
1244 }
1245
1246 val = !!cp->val;
1247
1248 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1249 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1250 goto failed;
1251 }
1252
1253 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1254 if (!cmd) {
1255 err = -ENOMEM;
1256 goto failed;
1257 }
1258
1259 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1260 if (err < 0) {
1261 mgmt_pending_remove(cmd);
1262 goto failed;
1263 }
1264
1265failed:
1266 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001267 return err;
1268}
1269
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001270static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001271{
1272 struct mgmt_mode *cp = data;
1273 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001274 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001275 int err;
1276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001278
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001279 if (!lmp_ssp_capable(hdev))
1280 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1281 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001282
Johan Hedberga7e80f22013-01-09 16:05:19 +02001283 if (cp->val != 0x00 && cp->val != 0x01)
1284 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1285 MGMT_STATUS_INVALID_PARAMS);
1286
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001287 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001288
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001289 val = !!cp->val;
1290
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001291 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001292 bool changed = false;
1293
1294 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1295 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1296 changed = true;
1297 }
1298
1299 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1300 if (err < 0)
1301 goto failed;
1302
1303 if (changed)
1304 err = new_settings(hdev, sk);
1305
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001306 goto failed;
1307 }
1308
1309 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001310 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1311 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001312 goto failed;
1313 }
1314
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001315 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1316 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1317 goto failed;
1318 }
1319
1320 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1321 if (!cmd) {
1322 err = -ENOMEM;
1323 goto failed;
1324 }
1325
1326 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1327 if (err < 0) {
1328 mgmt_pending_remove(cmd);
1329 goto failed;
1330 }
1331
1332failed:
1333 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001334 return err;
1335}
1336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001337static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001338{
1339 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001340 bool changed;
1341 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001342
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001343 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001344
Johan Hedberg56f87902013-10-02 13:43:13 +03001345 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001346 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001347 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001348
Johan Hedberga7e80f22013-01-09 16:05:19 +02001349 if (cp->val != 0x00 && cp->val != 0x01)
1350 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1351 MGMT_STATUS_INVALID_PARAMS);
1352
Marcel Holtmannee392692013-10-01 22:59:23 -07001353 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001354
Marcel Holtmannee392692013-10-01 22:59:23 -07001355 if (cp->val)
1356 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1357 else
1358 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1359
1360 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1361 if (err < 0)
1362 goto unlock;
1363
1364 if (changed)
1365 err = new_settings(hdev, sk);
1366
1367unlock:
1368 hci_dev_unlock(hdev);
1369 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001370}
1371
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001372static void le_enable_complete(struct hci_dev *hdev, u8 status)
1373{
1374 struct cmd_lookup match = { NULL, hdev };
1375
1376 if (status) {
1377 u8 mgmt_err = mgmt_status(status);
1378
1379 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1380 &mgmt_err);
1381 return;
1382 }
1383
1384 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1385
1386 new_settings(hdev, match.sk);
1387
1388 if (match.sk)
1389 sock_put(match.sk);
1390}
1391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001393{
1394 struct mgmt_mode *cp = data;
1395 struct hci_cp_write_le_host_supported hci_cp;
1396 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001397 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001398 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001399 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001401 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001402
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001403 if (!lmp_le_capable(hdev))
1404 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1405 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001406
Johan Hedberga7e80f22013-01-09 16:05:19 +02001407 if (cp->val != 0x00 && cp->val != 0x01)
1408 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1409 MGMT_STATUS_INVALID_PARAMS);
1410
Johan Hedbergc73eee92013-04-19 18:35:21 +03001411 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001412 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001413 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1414 MGMT_STATUS_REJECTED);
1415
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001416 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001417
1418 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001419 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001420
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001421 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001422 bool changed = false;
1423
1424 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1425 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1426 changed = true;
1427 }
1428
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001429 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1430 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1431 changed = true;
1432 }
1433
Johan Hedberg06199cf2012-02-22 16:37:11 +02001434 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1435 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001436 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001437
1438 if (changed)
1439 err = new_settings(hdev, sk);
1440
Johan Hedberg1de028c2012-02-29 19:55:35 -08001441 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001442 }
1443
Johan Hedberg4375f102013-09-25 13:26:10 +03001444 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1445 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001446 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001447 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001448 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001449 }
1450
1451 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1452 if (!cmd) {
1453 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001454 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001455 }
1456
1457 memset(&hci_cp, 0, sizeof(hci_cp));
1458
1459 if (val) {
1460 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001461 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001462 }
1463
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001464 hci_req_init(&req, hdev);
1465
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001466 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1467 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1468
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001469 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1470 &hci_cp);
1471
1472 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301473 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001474 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001475
Johan Hedberg1de028c2012-02-29 19:55:35 -08001476unlock:
1477 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001478 return err;
1479}
1480
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001481/* This is a helper function to test for pending mgmt commands that can
1482 * cause CoD or EIR HCI commands. We can only allow one such pending
1483 * mgmt command at a time since otherwise we cannot easily track what
1484 * the current values are, will be, and based on that calculate if a new
1485 * HCI command needs to be sent and if yes with what value.
1486 */
1487static bool pending_eir_or_class(struct hci_dev *hdev)
1488{
1489 struct pending_cmd *cmd;
1490
1491 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1492 switch (cmd->opcode) {
1493 case MGMT_OP_ADD_UUID:
1494 case MGMT_OP_REMOVE_UUID:
1495 case MGMT_OP_SET_DEV_CLASS:
1496 case MGMT_OP_SET_POWERED:
1497 return true;
1498 }
1499 }
1500
1501 return false;
1502}
1503
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001504static const u8 bluetooth_base_uuid[] = {
1505 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1506 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1507};
1508
1509static u8 get_uuid_size(const u8 *uuid)
1510{
1511 u32 val;
1512
1513 if (memcmp(uuid, bluetooth_base_uuid, 12))
1514 return 128;
1515
1516 val = get_unaligned_le32(&uuid[12]);
1517 if (val > 0xffff)
1518 return 32;
1519
1520 return 16;
1521}
1522
Johan Hedberg92da6092013-03-15 17:06:55 -05001523static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1524{
1525 struct pending_cmd *cmd;
1526
1527 hci_dev_lock(hdev);
1528
1529 cmd = mgmt_pending_find(mgmt_op, hdev);
1530 if (!cmd)
1531 goto unlock;
1532
1533 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1534 hdev->dev_class, 3);
1535
1536 mgmt_pending_remove(cmd);
1537
1538unlock:
1539 hci_dev_unlock(hdev);
1540}
1541
1542static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1543{
1544 BT_DBG("status 0x%02x", status);
1545
1546 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1547}
1548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001550{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001551 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001552 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001553 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001554 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001555 int err;
1556
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001557 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001559 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001560
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001561 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001562 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001563 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001564 goto failed;
1565 }
1566
Andre Guedes92c4c202012-06-07 19:05:44 -03001567 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001568 if (!uuid) {
1569 err = -ENOMEM;
1570 goto failed;
1571 }
1572
1573 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001574 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001575 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001576
Johan Hedbergde66aa62013-01-27 00:31:27 +02001577 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001578
Johan Hedberg890ea892013-03-15 17:06:52 -05001579 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001580
Johan Hedberg890ea892013-03-15 17:06:52 -05001581 update_class(&req);
1582 update_eir(&req);
1583
Johan Hedberg92da6092013-03-15 17:06:55 -05001584 err = hci_req_run(&req, add_uuid_complete);
1585 if (err < 0) {
1586 if (err != -ENODATA)
1587 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001589 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001590 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001591 goto failed;
1592 }
1593
1594 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001595 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001596 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001597 goto failed;
1598 }
1599
1600 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001601
1602failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001603 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001604 return err;
1605}
1606
Johan Hedberg24b78d02012-02-23 23:24:30 +02001607static bool enable_service_cache(struct hci_dev *hdev)
1608{
1609 if (!hdev_is_powered(hdev))
1610 return false;
1611
1612 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001613 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1614 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001615 return true;
1616 }
1617
1618 return false;
1619}
1620
Johan Hedberg92da6092013-03-15 17:06:55 -05001621static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1622{
1623 BT_DBG("status 0x%02x", status);
1624
1625 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1626}
1627
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001628static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001629 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001631 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001632 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001633 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001634 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05001635 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001636 int err, found;
1637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001638 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001640 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001641
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001642 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001644 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001645 goto unlock;
1646 }
1647
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001648 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1649 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001650
Johan Hedberg24b78d02012-02-23 23:24:30 +02001651 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001652 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001653 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001654 goto unlock;
1655 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001656
Johan Hedberg9246a862012-02-23 21:33:16 +02001657 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001658 }
1659
1660 found = 0;
1661
Johan Hedberg056341c2013-01-27 00:31:30 +02001662 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001663 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1664 continue;
1665
1666 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001667 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001668 found++;
1669 }
1670
1671 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001672 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001673 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001674 goto unlock;
1675 }
1676
Johan Hedberg9246a862012-02-23 21:33:16 +02001677update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001678 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001679
Johan Hedberg890ea892013-03-15 17:06:52 -05001680 update_class(&req);
1681 update_eir(&req);
1682
Johan Hedberg92da6092013-03-15 17:06:55 -05001683 err = hci_req_run(&req, remove_uuid_complete);
1684 if (err < 0) {
1685 if (err != -ENODATA)
1686 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001688 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001689 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001690 goto unlock;
1691 }
1692
1693 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001694 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001695 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001696 goto unlock;
1697 }
1698
1699 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001700
1701unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001702 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001703 return err;
1704}
1705
Johan Hedberg92da6092013-03-15 17:06:55 -05001706static void set_class_complete(struct hci_dev *hdev, u8 status)
1707{
1708 BT_DBG("status 0x%02x", status);
1709
1710 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1711}
1712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001713static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001715{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001716 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001717 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001718 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001719 int err;
1720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001721 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001722
Johan Hedberg56f87902013-10-02 13:43:13 +03001723 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001724 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1725 MGMT_STATUS_NOT_SUPPORTED);
1726
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001727 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001728
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001729 if (pending_eir_or_class(hdev)) {
1730 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1731 MGMT_STATUS_BUSY);
1732 goto unlock;
1733 }
1734
1735 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1736 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1737 MGMT_STATUS_INVALID_PARAMS);
1738 goto unlock;
1739 }
1740
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001741 hdev->major_class = cp->major;
1742 hdev->minor_class = cp->minor;
1743
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001744 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001745 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001746 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001747 goto unlock;
1748 }
1749
Johan Hedberg890ea892013-03-15 17:06:52 -05001750 hci_req_init(&req, hdev);
1751
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001752 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001753 hci_dev_unlock(hdev);
1754 cancel_delayed_work_sync(&hdev->service_cache);
1755 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001756 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001757 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001758
Johan Hedberg890ea892013-03-15 17:06:52 -05001759 update_class(&req);
1760
Johan Hedberg92da6092013-03-15 17:06:55 -05001761 err = hci_req_run(&req, set_class_complete);
1762 if (err < 0) {
1763 if (err != -ENODATA)
1764 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001765
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001766 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001767 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001768 goto unlock;
1769 }
1770
1771 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001772 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001773 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001774 goto unlock;
1775 }
1776
1777 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001778
Johan Hedbergb5235a62012-02-21 14:32:24 +02001779unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001780 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001781 return err;
1782}
1783
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001784static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001785 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001786{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001787 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001788 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001789 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001790
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001791 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001792
Johan Hedberg86742e12011-11-07 23:13:38 +02001793 expected_len = sizeof(*cp) + key_count *
1794 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001795 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001796 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001797 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001798 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001799 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001800 }
1801
Johan Hedberg4ae14302013-01-20 14:27:13 +02001802 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1803 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1804 MGMT_STATUS_INVALID_PARAMS);
1805
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001806 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001807 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001808
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001809 for (i = 0; i < key_count; i++) {
1810 struct mgmt_link_key_info *key = &cp->keys[i];
1811
1812 if (key->addr.type != BDADDR_BREDR)
1813 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1814 MGMT_STATUS_INVALID_PARAMS);
1815 }
1816
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001817 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001818
1819 hci_link_keys_clear(hdev);
1820
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001821 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001822 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001823 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001824 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001825
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001826 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001827 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001828
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001829 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001830 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001831 }
1832
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001833 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001834
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001835 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001836
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001837 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001838}
1839
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001840static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001841 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001842{
1843 struct mgmt_ev_device_unpaired ev;
1844
1845 bacpy(&ev.addr.bdaddr, bdaddr);
1846 ev.addr.type = addr_type;
1847
1848 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001849 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001850}
1851
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001852static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001853 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001854{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001855 struct mgmt_cp_unpair_device *cp = data;
1856 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001857 struct hci_cp_disconnect dc;
1858 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001859 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001860 int err;
1861
Johan Hedberga8a1d192011-11-10 15:54:38 +02001862 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001863 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1864 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001865
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001866 if (!bdaddr_type_is_valid(cp->addr.type))
1867 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1868 MGMT_STATUS_INVALID_PARAMS,
1869 &rp, sizeof(rp));
1870
Johan Hedberg118da702013-01-20 14:27:20 +02001871 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1872 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1873 MGMT_STATUS_INVALID_PARAMS,
1874 &rp, sizeof(rp));
1875
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001876 hci_dev_lock(hdev);
1877
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001878 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001879 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001880 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001881 goto unlock;
1882 }
1883
Andre Guedes591f47f2012-04-24 21:02:49 -03001884 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001885 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1886 else
1887 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001888
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001889 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001890 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001891 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001892 goto unlock;
1893 }
1894
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001895 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001896 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001897 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001898 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001899 else
1900 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001901 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001902 } else {
1903 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001904 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001905
Johan Hedberga8a1d192011-11-10 15:54:38 +02001906 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001907 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001908 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001909 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001910 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001911 }
1912
Johan Hedberg124f6e32012-02-09 13:50:12 +02001913 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001914 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001915 if (!cmd) {
1916 err = -ENOMEM;
1917 goto unlock;
1918 }
1919
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001920 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001921 dc.reason = 0x13; /* Remote User Terminated Connection */
1922 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1923 if (err < 0)
1924 mgmt_pending_remove(cmd);
1925
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001926unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001927 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001928 return err;
1929}
1930
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001931static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001932 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001933{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001934 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001935 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001936 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001937 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001938 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001939 int err;
1940
1941 BT_DBG("");
1942
Johan Hedberg06a63b12013-01-20 14:27:21 +02001943 memset(&rp, 0, sizeof(rp));
1944 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1945 rp.addr.type = cp->addr.type;
1946
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001947 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001948 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1949 MGMT_STATUS_INVALID_PARAMS,
1950 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001951
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001952 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001953
1954 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001955 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1956 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001957 goto failed;
1958 }
1959
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001960 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001961 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1962 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001963 goto failed;
1964 }
1965
Andre Guedes591f47f2012-04-24 21:02:49 -03001966 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001967 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1968 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001969 else
1970 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001971
Vishal Agarwalf9607272012-06-13 05:32:43 +05301972 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001973 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1974 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001975 goto failed;
1976 }
1977
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001978 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001979 if (!cmd) {
1980 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001981 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001982 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001983
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001984 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001985 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001986
1987 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1988 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001989 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001990
1991failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001992 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001993 return err;
1994}
1995
Andre Guedes57c14772012-04-24 21:02:50 -03001996static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001997{
1998 switch (link_type) {
1999 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002000 switch (addr_type) {
2001 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002002 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002003
Johan Hedberg48264f02011-11-09 13:58:58 +02002004 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002005 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002006 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002007 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002008
Johan Hedberg4c659c32011-11-07 23:13:39 +02002009 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002010 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002011 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002012 }
2013}
2014
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2016 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002017{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002018 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002019 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002020 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002021 int err;
2022 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002023
2024 BT_DBG("");
2025
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002026 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002027
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002028 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002029 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002030 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002031 goto unlock;
2032 }
2033
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002034 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002035 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2036 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002037 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002038 }
2039
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002040 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002041 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002042 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002043 err = -ENOMEM;
2044 goto unlock;
2045 }
2046
Johan Hedberg2784eb42011-01-21 13:56:35 +02002047 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002048 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002049 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2050 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002051 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002052 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002053 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002054 continue;
2055 i++;
2056 }
2057
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002058 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002059
Johan Hedberg4c659c32011-11-07 23:13:39 +02002060 /* Recalculate length in case of filtered SCO connections, etc */
2061 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002063 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002064 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002065
Johan Hedberga38528f2011-01-22 06:46:43 +02002066 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002067
2068unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002069 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002070 return err;
2071}
2072
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002073static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002074 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002075{
2076 struct pending_cmd *cmd;
2077 int err;
2078
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002079 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002080 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002081 if (!cmd)
2082 return -ENOMEM;
2083
Johan Hedbergd8457692012-02-17 14:24:57 +02002084 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002085 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002086 if (err < 0)
2087 mgmt_pending_remove(cmd);
2088
2089 return err;
2090}
2091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002094{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002095 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002096 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002097 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002098 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002099 int err;
2100
2101 BT_DBG("");
2102
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002103 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002104
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002105 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002106 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002107 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002108 goto failed;
2109 }
2110
Johan Hedbergd8457692012-02-17 14:24:57 +02002111 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002112 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002113 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002114 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002115 goto failed;
2116 }
2117
2118 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002119 struct mgmt_cp_pin_code_neg_reply ncp;
2120
2121 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002122
2123 BT_ERR("PIN code is not 16 bytes long");
2124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002125 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002126 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002127 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002128 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002129
2130 goto failed;
2131 }
2132
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002133 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002134 if (!cmd) {
2135 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002136 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002137 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002138
Johan Hedbergd8457692012-02-17 14:24:57 +02002139 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002141 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142
2143 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2144 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002145 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002146
2147failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002148 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002149 return err;
2150}
2151
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002152static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2153 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002154{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002155 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002156
2157 BT_DBG("");
2158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002159 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002160
2161 hdev->io_capability = cp->io_capability;
2162
2163 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002164 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002166 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002167
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002168 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2169 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002170}
2171
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002172static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002173{
2174 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002175 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002177 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002178 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2179 continue;
2180
Johan Hedberge9a416b2011-02-19 12:05:56 -03002181 if (cmd->user_data != conn)
2182 continue;
2183
2184 return cmd;
2185 }
2186
2187 return NULL;
2188}
2189
2190static void pairing_complete(struct pending_cmd *cmd, u8 status)
2191{
2192 struct mgmt_rp_pair_device rp;
2193 struct hci_conn *conn = cmd->user_data;
2194
Johan Hedbergba4e5642011-11-11 00:07:34 +02002195 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002196 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002197
Johan Hedbergaee9b212012-02-18 15:07:59 +02002198 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002200
2201 /* So we don't get further callbacks for this connection */
2202 conn->connect_cfm_cb = NULL;
2203 conn->security_cfm_cb = NULL;
2204 conn->disconn_cfm_cb = NULL;
2205
David Herrmann76a68ba2013-04-06 20:28:37 +02002206 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002207
Johan Hedberga664b5b2011-02-19 12:06:02 -03002208 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002209}
2210
2211static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2212{
2213 struct pending_cmd *cmd;
2214
2215 BT_DBG("status %u", status);
2216
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002217 cmd = find_pairing(conn);
2218 if (!cmd)
2219 BT_DBG("Unable to find a pending command");
2220 else
Johan Hedberge2113262012-02-18 15:20:03 +02002221 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002222}
2223
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302224static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2225{
2226 struct pending_cmd *cmd;
2227
2228 BT_DBG("status %u", status);
2229
2230 if (!status)
2231 return;
2232
2233 cmd = find_pairing(conn);
2234 if (!cmd)
2235 BT_DBG("Unable to find a pending command");
2236 else
2237 pairing_complete(cmd, mgmt_status(status));
2238}
2239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002240static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002241 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002242{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002243 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002244 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002245 struct pending_cmd *cmd;
2246 u8 sec_level, auth_type;
2247 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002248 int err;
2249
2250 BT_DBG("");
2251
Szymon Jancf950a30e2013-01-18 12:48:07 +01002252 memset(&rp, 0, sizeof(rp));
2253 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2254 rp.addr.type = cp->addr.type;
2255
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002256 if (!bdaddr_type_is_valid(cp->addr.type))
2257 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2258 MGMT_STATUS_INVALID_PARAMS,
2259 &rp, sizeof(rp));
2260
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002261 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002262
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002263 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002264 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2265 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002266 goto unlock;
2267 }
2268
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002269 sec_level = BT_SECURITY_MEDIUM;
2270 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002271 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002272 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002273 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002274
Andre Guedes591f47f2012-04-24 21:02:49 -03002275 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002276 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2277 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002278 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002279 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2280 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002281
Ville Tervo30e76272011-02-22 16:10:53 -03002282 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002283 int status;
2284
2285 if (PTR_ERR(conn) == -EBUSY)
2286 status = MGMT_STATUS_BUSY;
2287 else
2288 status = MGMT_STATUS_CONNECT_FAILED;
2289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002290 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002291 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002292 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002293 goto unlock;
2294 }
2295
2296 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002297 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002298 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002299 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002300 goto unlock;
2301 }
2302
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002303 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002304 if (!cmd) {
2305 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002306 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002307 goto unlock;
2308 }
2309
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002310 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002311 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002312 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302313 else
2314 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002315
Johan Hedberge9a416b2011-02-19 12:05:56 -03002316 conn->security_cfm_cb = pairing_complete_cb;
2317 conn->disconn_cfm_cb = pairing_complete_cb;
2318 conn->io_capability = cp->io_cap;
2319 cmd->user_data = conn;
2320
2321 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002322 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002323 pairing_complete(cmd, 0);
2324
2325 err = 0;
2326
2327unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002328 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002329 return err;
2330}
2331
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002332static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2333 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002334{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002335 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002336 struct pending_cmd *cmd;
2337 struct hci_conn *conn;
2338 int err;
2339
2340 BT_DBG("");
2341
Johan Hedberg28424702012-02-02 04:02:29 +02002342 hci_dev_lock(hdev);
2343
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002344 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002345 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002346 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002347 goto unlock;
2348 }
2349
Johan Hedberg28424702012-02-02 04:02:29 +02002350 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2351 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002352 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002354 goto unlock;
2355 }
2356
2357 conn = cmd->user_data;
2358
2359 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002362 goto unlock;
2363 }
2364
2365 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002367 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002368 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002369unlock:
2370 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002371 return err;
2372}
2373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002375 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002376 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002377{
Johan Hedberga5c29682011-02-19 12:05:57 -03002378 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002379 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002380 int err;
2381
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002382 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002383
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002384 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002385 err = cmd_complete(sk, hdev->id, mgmt_op,
2386 MGMT_STATUS_NOT_POWERED, addr,
2387 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002388 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002389 }
2390
Johan Hedberg1707c602013-03-15 17:07:15 -05002391 if (addr->type == BDADDR_BREDR)
2392 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002393 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002394 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002395
Johan Hedberg272d90d2012-02-09 15:26:12 +02002396 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002397 err = cmd_complete(sk, hdev->id, mgmt_op,
2398 MGMT_STATUS_NOT_CONNECTED, addr,
2399 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002400 goto done;
2401 }
2402
Johan Hedberg1707c602013-03-15 17:07:15 -05002403 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002404 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002405 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002406
Brian Gix5fe57d92011-12-21 16:12:13 -08002407 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002408 err = cmd_complete(sk, hdev->id, mgmt_op,
2409 MGMT_STATUS_SUCCESS, addr,
2410 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002411 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002412 err = cmd_complete(sk, hdev->id, mgmt_op,
2413 MGMT_STATUS_FAILED, addr,
2414 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002415
Brian Gix47c15e22011-11-16 13:53:14 -08002416 goto done;
2417 }
2418
Johan Hedberg1707c602013-03-15 17:07:15 -05002419 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002420 if (!cmd) {
2421 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002422 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002423 }
2424
Brian Gix0df4c182011-11-16 13:53:13 -08002425 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002426 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2427 struct hci_cp_user_passkey_reply cp;
2428
Johan Hedberg1707c602013-03-15 17:07:15 -05002429 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002430 cp.passkey = passkey;
2431 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2432 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002433 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2434 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002435
Johan Hedberga664b5b2011-02-19 12:06:02 -03002436 if (err < 0)
2437 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002438
Brian Gix0df4c182011-11-16 13:53:13 -08002439done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002440 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002441 return err;
2442}
2443
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302444static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2445 void *data, u16 len)
2446{
2447 struct mgmt_cp_pin_code_neg_reply *cp = data;
2448
2449 BT_DBG("");
2450
Johan Hedberg1707c602013-03-15 17:07:15 -05002451 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302452 MGMT_OP_PIN_CODE_NEG_REPLY,
2453 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2454}
2455
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002456static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2457 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002458{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002459 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002460
2461 BT_DBG("");
2462
2463 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002464 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002465 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002466
Johan Hedberg1707c602013-03-15 17:07:15 -05002467 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002468 MGMT_OP_USER_CONFIRM_REPLY,
2469 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002470}
2471
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002472static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002474{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002475 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002476
2477 BT_DBG("");
2478
Johan Hedberg1707c602013-03-15 17:07:15 -05002479 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2481 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002482}
2483
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002484static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2485 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002486{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002487 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002488
2489 BT_DBG("");
2490
Johan Hedberg1707c602013-03-15 17:07:15 -05002491 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002492 MGMT_OP_USER_PASSKEY_REPLY,
2493 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002494}
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002498{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002499 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002500
2501 BT_DBG("");
2502
Johan Hedberg1707c602013-03-15 17:07:15 -05002503 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002504 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2505 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002506}
2507
Johan Hedberg13928972013-03-15 17:07:00 -05002508static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002509{
Johan Hedberg13928972013-03-15 17:07:00 -05002510 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002511 struct hci_cp_write_local_name cp;
2512
Johan Hedberg13928972013-03-15 17:07:00 -05002513 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002514
Johan Hedberg890ea892013-03-15 17:06:52 -05002515 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002516}
2517
Johan Hedberg13928972013-03-15 17:07:00 -05002518static void set_name_complete(struct hci_dev *hdev, u8 status)
2519{
2520 struct mgmt_cp_set_local_name *cp;
2521 struct pending_cmd *cmd;
2522
2523 BT_DBG("status 0x%02x", status);
2524
2525 hci_dev_lock(hdev);
2526
2527 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2528 if (!cmd)
2529 goto unlock;
2530
2531 cp = cmd->param;
2532
2533 if (status)
2534 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2535 mgmt_status(status));
2536 else
2537 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2538 cp, sizeof(*cp));
2539
2540 mgmt_pending_remove(cmd);
2541
2542unlock:
2543 hci_dev_unlock(hdev);
2544}
2545
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002546static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002548{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002549 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002550 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002551 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002552 int err;
2553
2554 BT_DBG("");
2555
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002556 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002557
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002558 /* If the old values are the same as the new ones just return a
2559 * direct command complete event.
2560 */
2561 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2562 !memcmp(hdev->short_name, cp->short_name,
2563 sizeof(hdev->short_name))) {
2564 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2565 data, len);
2566 goto failed;
2567 }
2568
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002569 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002570
Johan Hedbergb5235a62012-02-21 14:32:24 +02002571 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002572 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002573
2574 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002575 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002576 if (err < 0)
2577 goto failed;
2578
2579 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002581
Johan Hedbergb5235a62012-02-21 14:32:24 +02002582 goto failed;
2583 }
2584
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002585 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002586 if (!cmd) {
2587 err = -ENOMEM;
2588 goto failed;
2589 }
2590
Johan Hedberg13928972013-03-15 17:07:00 -05002591 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2592
Johan Hedberg890ea892013-03-15 17:06:52 -05002593 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002594
2595 if (lmp_bredr_capable(hdev)) {
2596 update_name(&req);
2597 update_eir(&req);
2598 }
2599
2600 if (lmp_le_capable(hdev))
2601 hci_update_ad(&req);
2602
Johan Hedberg13928972013-03-15 17:07:00 -05002603 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002604 if (err < 0)
2605 mgmt_pending_remove(cmd);
2606
2607failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002608 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002609 return err;
2610}
2611
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002612static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002613 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002614{
Szymon Jancc35938b2011-03-22 13:12:21 +01002615 struct pending_cmd *cmd;
2616 int err;
2617
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002619
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002620 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002621
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002622 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002623 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002624 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002625 goto unlock;
2626 }
2627
Andre Guedes9a1a1992012-07-24 15:03:48 -03002628 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002631 goto unlock;
2632 }
2633
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002634 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002635 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002636 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002637 goto unlock;
2638 }
2639
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002640 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002641 if (!cmd) {
2642 err = -ENOMEM;
2643 goto unlock;
2644 }
2645
2646 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2647 if (err < 0)
2648 mgmt_pending_remove(cmd);
2649
2650unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002651 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002652 return err;
2653}
2654
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002655static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002656 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002657{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002658 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002659 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002660 int err;
2661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002663
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002664 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002665
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002666 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002667 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002668 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002669 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002670 else
Szymon Janca6785be2012-12-13 15:11:21 +01002671 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002673 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002674 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002675
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002676 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002677 return err;
2678}
2679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002680static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002681 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002682{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002683 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002684 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002685 int err;
2686
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002687 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002688
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002689 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002690
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002691 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002692 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002693 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002694 else
Szymon Janca6785be2012-12-13 15:11:21 +01002695 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002696
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002697 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002698 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002699
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002700 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002701 return err;
2702}
2703
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002704static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2705{
2706 struct pending_cmd *cmd;
2707 u8 type;
2708 int err;
2709
2710 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2711
2712 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2713 if (!cmd)
2714 return -ENOENT;
2715
2716 type = hdev->discovery.type;
2717
2718 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2719 &type, sizeof(type));
2720 mgmt_pending_remove(cmd);
2721
2722 return err;
2723}
2724
Andre Guedes7c307722013-04-30 15:29:28 -03002725static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2726{
2727 BT_DBG("status %d", status);
2728
2729 if (status) {
2730 hci_dev_lock(hdev);
2731 mgmt_start_discovery_failed(hdev, status);
2732 hci_dev_unlock(hdev);
2733 return;
2734 }
2735
2736 hci_dev_lock(hdev);
2737 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2738 hci_dev_unlock(hdev);
2739
2740 switch (hdev->discovery.type) {
2741 case DISCOV_TYPE_LE:
2742 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002743 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002744 break;
2745
2746 case DISCOV_TYPE_INTERLEAVED:
2747 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002748 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002749 break;
2750
2751 case DISCOV_TYPE_BREDR:
2752 break;
2753
2754 default:
2755 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2756 }
2757}
2758
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002759static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002760 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002761{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002762 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002763 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002764 struct hci_cp_le_set_scan_param param_cp;
2765 struct hci_cp_le_set_scan_enable enable_cp;
2766 struct hci_cp_inquiry inq_cp;
2767 struct hci_request req;
2768 /* General inquiry access code (GIAC) */
2769 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002770 int err;
2771
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002772 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002773
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002774 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002775
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002776 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002777 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002778 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002779 goto failed;
2780 }
2781
Andre Guedes642be6c2012-03-21 00:03:37 -03002782 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2783 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2784 MGMT_STATUS_BUSY);
2785 goto failed;
2786 }
2787
Johan Hedbergff9ef572012-01-04 14:23:45 +02002788 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002789 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002790 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002791 goto failed;
2792 }
2793
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002794 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002795 if (!cmd) {
2796 err = -ENOMEM;
2797 goto failed;
2798 }
2799
Andre Guedes4aab14e2012-02-17 20:39:36 -03002800 hdev->discovery.type = cp->type;
2801
Andre Guedes7c307722013-04-30 15:29:28 -03002802 hci_req_init(&req, hdev);
2803
Andre Guedes4aab14e2012-02-17 20:39:36 -03002804 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002805 case DISCOV_TYPE_BREDR:
Johan Hedberg56f87902013-10-02 13:43:13 +03002806 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002807 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2808 MGMT_STATUS_NOT_SUPPORTED);
2809 mgmt_pending_remove(cmd);
2810 goto failed;
2811 }
2812
Andre Guedes7c307722013-04-30 15:29:28 -03002813 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2814 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2815 MGMT_STATUS_BUSY);
2816 mgmt_pending_remove(cmd);
2817 goto failed;
2818 }
2819
2820 hci_inquiry_cache_flush(hdev);
2821
2822 memset(&inq_cp, 0, sizeof(inq_cp));
2823 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002824 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002825 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002826 break;
2827
2828 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002829 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002830 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002831 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2832 MGMT_STATUS_NOT_SUPPORTED);
2833 mgmt_pending_remove(cmd);
2834 goto failed;
2835 }
2836
Andre Guedes7c307722013-04-30 15:29:28 -03002837 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002838 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002839 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2840 MGMT_STATUS_NOT_SUPPORTED);
2841 mgmt_pending_remove(cmd);
2842 goto failed;
2843 }
2844
Andre Guedes7c307722013-04-30 15:29:28 -03002845 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2846 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2847 MGMT_STATUS_REJECTED);
2848 mgmt_pending_remove(cmd);
2849 goto failed;
2850 }
2851
2852 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2853 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2854 MGMT_STATUS_BUSY);
2855 mgmt_pending_remove(cmd);
2856 goto failed;
2857 }
2858
2859 memset(&param_cp, 0, sizeof(param_cp));
2860 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002861 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2862 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002863 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2864 &param_cp);
2865
2866 memset(&enable_cp, 0, sizeof(enable_cp));
2867 enable_cp.enable = LE_SCAN_ENABLE;
2868 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2869 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2870 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002871 break;
2872
Andre Guedesf39799f2012-02-17 20:39:35 -03002873 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002874 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2875 MGMT_STATUS_INVALID_PARAMS);
2876 mgmt_pending_remove(cmd);
2877 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002878 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002879
Andre Guedes7c307722013-04-30 15:29:28 -03002880 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002881 if (err < 0)
2882 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002883 else
2884 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002885
2886failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002887 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002888 return err;
2889}
2890
Andre Guedes1183fdc2013-04-30 15:29:35 -03002891static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2892{
2893 struct pending_cmd *cmd;
2894 int err;
2895
2896 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2897 if (!cmd)
2898 return -ENOENT;
2899
2900 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2901 &hdev->discovery.type, sizeof(hdev->discovery.type));
2902 mgmt_pending_remove(cmd);
2903
2904 return err;
2905}
2906
Andre Guedes0e05bba2013-04-30 15:29:33 -03002907static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2908{
2909 BT_DBG("status %d", status);
2910
2911 hci_dev_lock(hdev);
2912
2913 if (status) {
2914 mgmt_stop_discovery_failed(hdev, status);
2915 goto unlock;
2916 }
2917
2918 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2919
2920unlock:
2921 hci_dev_unlock(hdev);
2922}
2923
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002924static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002925 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002926{
Johan Hedbergd9306502012-02-20 23:25:18 +02002927 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002928 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002929 struct hci_cp_remote_name_req_cancel cp;
2930 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002931 struct hci_request req;
2932 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002933 int err;
2934
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002935 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002936
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002937 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002938
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002939 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002940 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002941 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2942 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002943 goto unlock;
2944 }
2945
2946 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002947 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002948 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2949 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002950 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002951 }
2952
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002953 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002954 if (!cmd) {
2955 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002956 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002957 }
2958
Andre Guedes0e05bba2013-04-30 15:29:33 -03002959 hci_req_init(&req, hdev);
2960
Andre Guedese0d9727e2012-03-20 15:15:36 -03002961 switch (hdev->discovery.state) {
2962 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002963 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2964 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2965 } else {
2966 cancel_delayed_work(&hdev->le_scan_disable);
2967
2968 memset(&enable_cp, 0, sizeof(enable_cp));
2969 enable_cp.enable = LE_SCAN_DISABLE;
2970 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2971 sizeof(enable_cp), &enable_cp);
2972 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002973
Andre Guedese0d9727e2012-03-20 15:15:36 -03002974 break;
2975
2976 case DISCOVERY_RESOLVING:
2977 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002978 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002979 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002980 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002981 err = cmd_complete(sk, hdev->id,
2982 MGMT_OP_STOP_DISCOVERY, 0,
2983 &mgmt_cp->type,
2984 sizeof(mgmt_cp->type));
2985 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2986 goto unlock;
2987 }
2988
2989 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002990 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2991 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002992
2993 break;
2994
2995 default:
2996 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002997
2998 mgmt_pending_remove(cmd);
2999 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3000 MGMT_STATUS_FAILED, &mgmt_cp->type,
3001 sizeof(mgmt_cp->type));
3002 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003003 }
3004
Andre Guedes0e05bba2013-04-30 15:29:33 -03003005 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003006 if (err < 0)
3007 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003008 else
3009 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003010
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003011unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003012 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003013 return err;
3014}
3015
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003016static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003017 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003018{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003019 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003020 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003021 int err;
3022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003023 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003024
Johan Hedberg561aafb2012-01-04 13:31:59 +02003025 hci_dev_lock(hdev);
3026
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003027 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003028 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003030 goto failed;
3031 }
3032
Johan Hedberga198e7b2012-02-17 14:27:06 +02003033 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003034 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003035 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003037 goto failed;
3038 }
3039
3040 if (cp->name_known) {
3041 e->name_state = NAME_KNOWN;
3042 list_del(&e->list);
3043 } else {
3044 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003045 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003046 }
3047
Johan Hedberge3846622013-01-09 15:29:33 +02003048 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3049 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003050
3051failed:
3052 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003053 return err;
3054}
3055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003056static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003057 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003058{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003059 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003060 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003061 int err;
3062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003063 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003064
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003065 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003066 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3067 MGMT_STATUS_INVALID_PARAMS,
3068 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003069
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003070 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003071
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003072 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003073 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003074 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003075 else
Szymon Janca6785be2012-12-13 15:11:21 +01003076 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003077
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003078 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003079 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003080
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003081 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003082
3083 return err;
3084}
3085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003089 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003090 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003091 int err;
3092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003093 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003094
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003095 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003096 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3097 MGMT_STATUS_INVALID_PARAMS,
3098 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003099
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003100 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003101
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003102 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003103 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003104 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003105 else
Szymon Janca6785be2012-12-13 15:11:21 +01003106 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003107
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003108 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003109 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003110
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003111 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003112
3113 return err;
3114}
3115
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003116static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3117 u16 len)
3118{
3119 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003120 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003121 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003122 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003123
3124 BT_DBG("%s", hdev->name);
3125
Szymon Jancc72d4b82012-03-16 16:02:57 +01003126 source = __le16_to_cpu(cp->source);
3127
3128 if (source > 0x0002)
3129 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3130 MGMT_STATUS_INVALID_PARAMS);
3131
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003132 hci_dev_lock(hdev);
3133
Szymon Jancc72d4b82012-03-16 16:02:57 +01003134 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003135 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3136 hdev->devid_product = __le16_to_cpu(cp->product);
3137 hdev->devid_version = __le16_to_cpu(cp->version);
3138
3139 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3140
Johan Hedberg890ea892013-03-15 17:06:52 -05003141 hci_req_init(&req, hdev);
3142 update_eir(&req);
3143 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003144
3145 hci_dev_unlock(hdev);
3146
3147 return err;
3148}
3149
Johan Hedberg4375f102013-09-25 13:26:10 +03003150static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3151{
3152 struct cmd_lookup match = { NULL, hdev };
3153
3154 if (status) {
3155 u8 mgmt_err = mgmt_status(status);
3156
3157 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3158 cmd_status_rsp, &mgmt_err);
3159 return;
3160 }
3161
3162 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3163 &match);
3164
3165 new_settings(hdev, match.sk);
3166
3167 if (match.sk)
3168 sock_put(match.sk);
3169}
3170
3171static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3172{
3173 struct mgmt_mode *cp = data;
3174 struct pending_cmd *cmd;
3175 struct hci_request req;
3176 u8 val, enabled;
3177 int err;
3178
3179 BT_DBG("request for %s", hdev->name);
3180
3181 if (!lmp_le_capable(hdev))
3182 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3183 MGMT_STATUS_NOT_SUPPORTED);
3184
3185 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3186 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3187 MGMT_STATUS_REJECTED);
3188
3189 if (cp->val != 0x00 && cp->val != 0x01)
3190 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3191 MGMT_STATUS_INVALID_PARAMS);
3192
3193 hci_dev_lock(hdev);
3194
3195 val = !!cp->val;
3196 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3197
3198 if (!hdev_is_powered(hdev) || val == enabled) {
3199 bool changed = false;
3200
3201 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3202 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3203 changed = true;
3204 }
3205
3206 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3207 if (err < 0)
3208 goto unlock;
3209
3210 if (changed)
3211 err = new_settings(hdev, sk);
3212
3213 goto unlock;
3214 }
3215
3216 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3217 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3218 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3219 MGMT_STATUS_BUSY);
3220 goto unlock;
3221 }
3222
3223 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3224 if (!cmd) {
3225 err = -ENOMEM;
3226 goto unlock;
3227 }
3228
3229 hci_req_init(&req, hdev);
3230
3231 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3232
3233 err = hci_req_run(&req, set_advertising_complete);
3234 if (err < 0)
3235 mgmt_pending_remove(cmd);
3236
3237unlock:
3238 hci_dev_unlock(hdev);
3239 return err;
3240}
3241
Johan Hedberg33e38b32013-03-15 17:07:05 -05003242static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3243{
3244 struct pending_cmd *cmd;
3245
3246 BT_DBG("status 0x%02x", status);
3247
3248 hci_dev_lock(hdev);
3249
3250 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3251 if (!cmd)
3252 goto unlock;
3253
3254 if (status) {
3255 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3256 mgmt_status(status));
3257 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003258 struct mgmt_mode *cp = cmd->param;
3259
3260 if (cp->val)
3261 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3262 else
3263 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3264
Johan Hedberg33e38b32013-03-15 17:07:05 -05003265 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3266 new_settings(hdev, cmd->sk);
3267 }
3268
3269 mgmt_pending_remove(cmd);
3270
3271unlock:
3272 hci_dev_unlock(hdev);
3273}
3274
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003275static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003276 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003277{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003278 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003279 struct pending_cmd *cmd;
3280 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003281 int err;
3282
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003283 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003284
Johan Hedberg56f87902013-10-02 13:43:13 +03003285 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3286 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003287 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3288 MGMT_STATUS_NOT_SUPPORTED);
3289
Johan Hedberga7e80f22013-01-09 16:05:19 +02003290 if (cp->val != 0x00 && cp->val != 0x01)
3291 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3292 MGMT_STATUS_INVALID_PARAMS);
3293
Johan Hedberg5400c042012-02-21 16:40:33 +02003294 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003295 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003296 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003297
3298 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003299 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003300 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003301
3302 hci_dev_lock(hdev);
3303
Johan Hedberg05cbf292013-03-15 17:07:07 -05003304 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3305 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3306 MGMT_STATUS_BUSY);
3307 goto unlock;
3308 }
3309
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003310 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3311 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3312 hdev);
3313 goto unlock;
3314 }
3315
Johan Hedberg33e38b32013-03-15 17:07:05 -05003316 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3317 data, len);
3318 if (!cmd) {
3319 err = -ENOMEM;
3320 goto unlock;
3321 }
3322
3323 hci_req_init(&req, hdev);
3324
Johan Hedberg406d7802013-03-15 17:07:09 -05003325 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003326
3327 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003328 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003329 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003330 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003331 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003332 }
3333
Johan Hedberg33e38b32013-03-15 17:07:05 -05003334unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003335 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003336
Antti Julkuf6422ec2011-06-22 13:11:56 +03003337 return err;
3338}
3339
Johan Hedberg3f706b72013-01-20 14:27:16 +02003340static bool ltk_is_valid(struct mgmt_ltk_info *key)
3341{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003342 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3343 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003344 if (key->master != 0x00 && key->master != 0x01)
3345 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003346 if (!bdaddr_type_is_le(key->addr.type))
3347 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003348 return true;
3349}
3350
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003351static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003352 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003353{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003354 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3355 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003356 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003357
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003358 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003359
3360 expected_len = sizeof(*cp) + key_count *
3361 sizeof(struct mgmt_ltk_info);
3362 if (expected_len != len) {
3363 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003364 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003365 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003366 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003367 }
3368
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003369 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003370
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003371 for (i = 0; i < key_count; i++) {
3372 struct mgmt_ltk_info *key = &cp->keys[i];
3373
Johan Hedberg3f706b72013-01-20 14:27:16 +02003374 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003375 return cmd_status(sk, hdev->id,
3376 MGMT_OP_LOAD_LONG_TERM_KEYS,
3377 MGMT_STATUS_INVALID_PARAMS);
3378 }
3379
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003380 hci_dev_lock(hdev);
3381
3382 hci_smp_ltks_clear(hdev);
3383
3384 for (i = 0; i < key_count; i++) {
3385 struct mgmt_ltk_info *key = &cp->keys[i];
3386 u8 type;
3387
3388 if (key->master)
3389 type = HCI_SMP_LTK;
3390 else
3391 type = HCI_SMP_LTK_SLAVE;
3392
Hemant Gupta4596fde2012-04-16 14:57:40 +05303393 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003394 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003395 type, 0, key->authenticated, key->val,
3396 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003397 }
3398
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003399 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3400 NULL, 0);
3401
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003402 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003403
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003404 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003405}
3406
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003407static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003408 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3409 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003410 bool var_len;
3411 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003412} mgmt_handlers[] = {
3413 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003414 { read_version, false, MGMT_READ_VERSION_SIZE },
3415 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3416 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3417 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3418 { set_powered, false, MGMT_SETTING_SIZE },
3419 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3420 { set_connectable, false, MGMT_SETTING_SIZE },
3421 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3422 { set_pairable, false, MGMT_SETTING_SIZE },
3423 { set_link_security, false, MGMT_SETTING_SIZE },
3424 { set_ssp, false, MGMT_SETTING_SIZE },
3425 { set_hs, false, MGMT_SETTING_SIZE },
3426 { set_le, false, MGMT_SETTING_SIZE },
3427 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3428 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3429 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3430 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3431 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3432 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3433 { disconnect, false, MGMT_DISCONNECT_SIZE },
3434 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3435 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3436 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3437 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3438 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3439 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3440 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3441 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3442 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3443 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3444 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3445 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3446 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3447 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3448 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3449 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3450 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3451 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3452 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003453 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003454 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003455};
3456
3457
Johan Hedberg03811012010-12-08 00:21:06 +02003458int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3459{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003460 void *buf;
3461 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003462 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003463 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003464 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003465 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003466 int err;
3467
3468 BT_DBG("got %zu bytes", msglen);
3469
3470 if (msglen < sizeof(*hdr))
3471 return -EINVAL;
3472
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003473 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003474 if (!buf)
3475 return -ENOMEM;
3476
3477 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3478 err = -EFAULT;
3479 goto done;
3480 }
3481
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003482 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003483 opcode = __le16_to_cpu(hdr->opcode);
3484 index = __le16_to_cpu(hdr->index);
3485 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003486
3487 if (len != msglen - sizeof(*hdr)) {
3488 err = -EINVAL;
3489 goto done;
3490 }
3491
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003492 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003493 hdev = hci_dev_get(index);
3494 if (!hdev) {
3495 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003496 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003497 goto done;
3498 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003499
3500 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3501 err = cmd_status(sk, index, opcode,
3502 MGMT_STATUS_INVALID_INDEX);
3503 goto done;
3504 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003505 }
3506
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003507 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003508 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003509 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003510 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003511 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003512 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003513 }
3514
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003515 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003516 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003517 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003518 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003519 goto done;
3520 }
3521
Johan Hedbergbe22b542012-03-01 22:24:41 +02003522 handler = &mgmt_handlers[opcode];
3523
3524 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003525 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003526 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003527 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003528 goto done;
3529 }
3530
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003531 if (hdev)
3532 mgmt_init_hdev(sk, hdev);
3533
3534 cp = buf + sizeof(*hdr);
3535
Johan Hedbergbe22b542012-03-01 22:24:41 +02003536 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003537 if (err < 0)
3538 goto done;
3539
Johan Hedberg03811012010-12-08 00:21:06 +02003540 err = msglen;
3541
3542done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003543 if (hdev)
3544 hci_dev_put(hdev);
3545
Johan Hedberg03811012010-12-08 00:21:06 +02003546 kfree(buf);
3547 return err;
3548}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003549
Johan Hedberg744cf192011-11-08 20:40:14 +02003550int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003551{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003552 if (!mgmt_valid_hdev(hdev))
3553 return -ENOTSUPP;
3554
Johan Hedberg744cf192011-11-08 20:40:14 +02003555 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003556}
3557
Johan Hedberg744cf192011-11-08 20:40:14 +02003558int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003559{
Johan Hedberg5f159032012-03-02 03:13:19 +02003560 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003561
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003562 if (!mgmt_valid_hdev(hdev))
3563 return -ENOTSUPP;
3564
Johan Hedberg744cf192011-11-08 20:40:14 +02003565 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003566
Johan Hedberg744cf192011-11-08 20:40:14 +02003567 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003568}
3569
Johan Hedberg890ea892013-03-15 17:06:52 -05003570static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003571{
Johan Hedberg890ea892013-03-15 17:06:52 -05003572 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003573 u8 scan = 0;
3574
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003575 /* Ensure that fast connectable is disabled. This function will
3576 * not do anything if the page scan parameters are already what
3577 * they should be.
3578 */
3579 write_fast_connectable(req, false);
3580
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003581 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3582 scan |= SCAN_PAGE;
3583 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3584 scan |= SCAN_INQUIRY;
3585
Johan Hedberg890ea892013-03-15 17:06:52 -05003586 if (scan)
3587 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003588}
3589
Johan Hedberg229ab392013-03-15 17:06:53 -05003590static void powered_complete(struct hci_dev *hdev, u8 status)
3591{
3592 struct cmd_lookup match = { NULL, hdev };
3593
3594 BT_DBG("status 0x%02x", status);
3595
3596 hci_dev_lock(hdev);
3597
3598 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3599
3600 new_settings(hdev, match.sk);
3601
3602 hci_dev_unlock(hdev);
3603
3604 if (match.sk)
3605 sock_put(match.sk);
3606}
3607
Johan Hedberg70da6242013-03-15 17:06:51 -05003608static int powered_update_hci(struct hci_dev *hdev)
3609{
Johan Hedberg890ea892013-03-15 17:06:52 -05003610 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003611 u8 link_sec;
3612
Johan Hedberg890ea892013-03-15 17:06:52 -05003613 hci_req_init(&req, hdev);
3614
Johan Hedberg70da6242013-03-15 17:06:51 -05003615 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3616 !lmp_host_ssp_capable(hdev)) {
3617 u8 ssp = 1;
3618
Johan Hedberg890ea892013-03-15 17:06:52 -05003619 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003620 }
3621
Johan Hedbergc73eee92013-04-19 18:35:21 +03003622 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3623 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003624 struct hci_cp_write_le_host_supported cp;
3625
3626 cp.le = 1;
3627 cp.simul = lmp_le_br_capable(hdev);
3628
3629 /* Check first if we already have the right
3630 * host state (host features set)
3631 */
3632 if (cp.le != lmp_host_le_capable(hdev) ||
3633 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003634 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3635 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003636 }
3637
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003638 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3639 u8 adv = 0x01;
3640
3641 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3642 }
3643
Johan Hedberg70da6242013-03-15 17:06:51 -05003644 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3645 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003646 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3647 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003648
3649 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003650 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3651 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003652 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003653 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003654 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003655 }
3656
Johan Hedberg229ab392013-03-15 17:06:53 -05003657 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003658}
3659
Johan Hedberg744cf192011-11-08 20:40:14 +02003660int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003661{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003662 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003663 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3664 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003665 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003666
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003667 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3668 return 0;
3669
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003670 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003671 if (powered_update_hci(hdev) == 0)
3672 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003673
Johan Hedberg229ab392013-03-15 17:06:53 -05003674 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3675 &match);
3676 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003677 }
3678
Johan Hedberg229ab392013-03-15 17:06:53 -05003679 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3680 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3681
3682 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3683 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3684 zero_cod, sizeof(zero_cod), NULL);
3685
3686new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003687 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003688
3689 if (match.sk)
3690 sock_put(match.sk);
3691
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003692 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003693}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003694
Johan Hedberg96570ff2013-05-29 09:51:29 +03003695int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3696{
3697 struct pending_cmd *cmd;
3698 u8 status;
3699
3700 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3701 if (!cmd)
3702 return -ENOENT;
3703
3704 if (err == -ERFKILL)
3705 status = MGMT_STATUS_RFKILLED;
3706 else
3707 status = MGMT_STATUS_FAILED;
3708
3709 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3710
3711 mgmt_pending_remove(cmd);
3712
3713 return err;
3714}
3715
Johan Hedberg744cf192011-11-08 20:40:14 +02003716int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003717{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003718 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003719 bool changed = false;
3720 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003721
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003722 if (discoverable) {
3723 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3724 changed = true;
3725 } else {
3726 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3727 changed = true;
3728 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003729
Johan Hedberged9b5f22012-02-21 20:47:06 +02003730 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003731 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003732
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003733 if (changed)
3734 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003735
Johan Hedberg73f22f62010-12-29 16:00:25 +02003736 if (match.sk)
3737 sock_put(match.sk);
3738
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003739 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003740}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003741
Johan Hedberg744cf192011-11-08 20:40:14 +02003742int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003743{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003744 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003745 bool changed = false;
3746 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003747
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003748 if (connectable) {
3749 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3750 changed = true;
3751 } else {
3752 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3753 changed = true;
3754 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003755
Johan Hedberg2b76f452013-03-15 17:07:04 -05003756 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003757
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003758 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003759 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003760
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003761 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003762}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003763
Johan Hedberg744cf192011-11-08 20:40:14 +02003764int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003765{
Johan Hedbergca69b792011-11-11 18:10:00 +02003766 u8 mgmt_err = mgmt_status(status);
3767
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003768 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003769 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003770 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003771
3772 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003773 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003774 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003775
3776 return 0;
3777}
3778
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003779int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3780 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003781{
Johan Hedberg86742e12011-11-07 23:13:38 +02003782 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003783
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003784 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003785
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003786 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003787 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003788 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003789 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003790 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003791 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003792
Johan Hedberg744cf192011-11-08 20:40:14 +02003793 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003794}
Johan Hedbergf7520542011-01-20 12:34:39 +02003795
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003796int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3797{
3798 struct mgmt_ev_new_long_term_key ev;
3799
3800 memset(&ev, 0, sizeof(ev));
3801
3802 ev.store_hint = persistent;
3803 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003804 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003805 ev.key.authenticated = key->authenticated;
3806 ev.key.enc_size = key->enc_size;
3807 ev.key.ediv = key->ediv;
3808
3809 if (key->type == HCI_SMP_LTK)
3810 ev.key.master = 1;
3811
3812 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3813 memcpy(ev.key.val, key->val, sizeof(key->val));
3814
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003815 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3816 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003817}
3818
Johan Hedbergafc747a2012-01-15 18:11:07 +02003819int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003820 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3821 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003822{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003823 char buf[512];
3824 struct mgmt_ev_device_connected *ev = (void *) buf;
3825 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003826
Johan Hedbergb644ba32012-01-17 21:48:47 +02003827 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003828 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003829
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003830 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003831
Johan Hedbergb644ba32012-01-17 21:48:47 +02003832 if (name_len > 0)
3833 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003834 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003835
3836 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003837 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003838 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003839
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003840 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003841
3842 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003843 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003844}
3845
Johan Hedberg8962ee72011-01-20 12:40:27 +02003846static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3847{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003848 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003849 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003850 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003851
Johan Hedberg88c3df12012-02-09 14:27:38 +02003852 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3853 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003854
Johan Hedbergaee9b212012-02-18 15:07:59 +02003855 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003856 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003857
3858 *sk = cmd->sk;
3859 sock_hold(*sk);
3860
Johan Hedberga664b5b2011-02-19 12:06:02 -03003861 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003862}
3863
Johan Hedberg124f6e32012-02-09 13:50:12 +02003864static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003865{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003866 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003867 struct mgmt_cp_unpair_device *cp = cmd->param;
3868 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003869
3870 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003871 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3872 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003873
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003874 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3875
Johan Hedbergaee9b212012-02-18 15:07:59 +02003876 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003877
3878 mgmt_pending_remove(cmd);
3879}
3880
Johan Hedbergafc747a2012-01-15 18:11:07 +02003881int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003882 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003883{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003884 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003885 struct sock *sk = NULL;
3886 int err;
3887
Johan Hedberg744cf192011-11-08 20:40:14 +02003888 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003889
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003890 bacpy(&ev.addr.bdaddr, bdaddr);
3891 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3892 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003893
Johan Hedbergafc747a2012-01-15 18:11:07 +02003894 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003895 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003896
3897 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003898 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003899
Johan Hedberg124f6e32012-02-09 13:50:12 +02003900 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003901 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003902
Johan Hedberg8962ee72011-01-20 12:40:27 +02003903 return err;
3904}
3905
Johan Hedberg88c3df12012-02-09 14:27:38 +02003906int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003907 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003908{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003909 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003910 struct pending_cmd *cmd;
3911 int err;
3912
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003913 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3914 hdev);
3915
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003916 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003917 if (!cmd)
3918 return -ENOENT;
3919
Johan Hedberg88c3df12012-02-09 14:27:38 +02003920 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003921 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003922
Johan Hedberg88c3df12012-02-09 14:27:38 +02003923 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003924 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003925
Johan Hedberga664b5b2011-02-19 12:06:02 -03003926 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003927
3928 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003929}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003930
Johan Hedberg48264f02011-11-09 13:58:58 +02003931int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003932 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003933{
3934 struct mgmt_ev_connect_failed ev;
3935
Johan Hedberg4c659c32011-11-07 23:13:39 +02003936 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003937 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003938 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003939
Johan Hedberg744cf192011-11-08 20:40:14 +02003940 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003941}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003942
Johan Hedberg744cf192011-11-08 20:40:14 +02003943int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003944{
3945 struct mgmt_ev_pin_code_request ev;
3946
Johan Hedbergd8457692012-02-17 14:24:57 +02003947 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003948 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003949 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003950
Johan Hedberg744cf192011-11-08 20:40:14 +02003951 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003952 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003953}
3954
Johan Hedberg744cf192011-11-08 20:40:14 +02003955int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003956 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003957{
3958 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003959 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003960 int err;
3961
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003962 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003963 if (!cmd)
3964 return -ENOENT;
3965
Johan Hedbergd8457692012-02-17 14:24:57 +02003966 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003967 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003968
Johan Hedbergaee9b212012-02-18 15:07:59 +02003969 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003970 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003971
Johan Hedberga664b5b2011-02-19 12:06:02 -03003972 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003973
3974 return err;
3975}
3976
Johan Hedberg744cf192011-11-08 20:40:14 +02003977int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003978 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003979{
3980 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003981 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003982 int err;
3983
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003984 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003985 if (!cmd)
3986 return -ENOENT;
3987
Johan Hedbergd8457692012-02-17 14:24:57 +02003988 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003989 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003990
Johan Hedbergaee9b212012-02-18 15:07:59 +02003991 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003992 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003993
Johan Hedberga664b5b2011-02-19 12:06:02 -03003994 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003995
3996 return err;
3997}
Johan Hedberga5c29682011-02-19 12:05:57 -03003998
Johan Hedberg744cf192011-11-08 20:40:14 +02003999int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004000 u8 link_type, u8 addr_type, __le32 value,
4001 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004002{
4003 struct mgmt_ev_user_confirm_request ev;
4004
Johan Hedberg744cf192011-11-08 20:40:14 +02004005 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004006
Johan Hedberg272d90d2012-02-09 15:26:12 +02004007 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004008 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004009 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004010 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004011
Johan Hedberg744cf192011-11-08 20:40:14 +02004012 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004013 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004014}
4015
Johan Hedberg272d90d2012-02-09 15:26:12 +02004016int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004017 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004018{
4019 struct mgmt_ev_user_passkey_request ev;
4020
4021 BT_DBG("%s", hdev->name);
4022
Johan Hedberg272d90d2012-02-09 15:26:12 +02004023 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004024 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004025
4026 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004027 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004028}
4029
Brian Gix0df4c182011-11-16 13:53:13 -08004030static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004031 u8 link_type, u8 addr_type, u8 status,
4032 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004033{
4034 struct pending_cmd *cmd;
4035 struct mgmt_rp_user_confirm_reply rp;
4036 int err;
4037
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004038 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004039 if (!cmd)
4040 return -ENOENT;
4041
Johan Hedberg272d90d2012-02-09 15:26:12 +02004042 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004043 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004044 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004045 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004046
Johan Hedberga664b5b2011-02-19 12:06:02 -03004047 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004048
4049 return err;
4050}
4051
Johan Hedberg744cf192011-11-08 20:40:14 +02004052int mgmt_user_confirm_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)
Johan Hedberga5c29682011-02-19 12:05:57 -03004054{
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_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004057}
4058
Johan Hedberg272d90d2012-02-09 15:26:12 +02004059int mgmt_user_confirm_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)
Johan Hedberga5c29682011-02-19 12:05:57 -03004061{
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_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004065}
Johan Hedberg2a611692011-02-19 12:06:00 -03004066
Brian Gix604086b2011-11-23 08:28:33 -08004067int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004068 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004069{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004070 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004071 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004072}
4073
Johan Hedberg272d90d2012-02-09 15:26:12 +02004074int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004075 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004076{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004077 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004078 status,
4079 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004080}
4081
Johan Hedberg92a25252012-09-06 18:39:26 +03004082int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4083 u8 link_type, u8 addr_type, u32 passkey,
4084 u8 entered)
4085{
4086 struct mgmt_ev_passkey_notify ev;
4087
4088 BT_DBG("%s", hdev->name);
4089
4090 bacpy(&ev.addr.bdaddr, bdaddr);
4091 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4092 ev.passkey = __cpu_to_le32(passkey);
4093 ev.entered = entered;
4094
4095 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4096}
4097
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004098int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004099 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004100{
4101 struct mgmt_ev_auth_failed ev;
4102
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004103 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004104 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004105 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004106
Johan Hedberg744cf192011-11-08 20:40:14 +02004107 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004108}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004109
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004110int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4111{
4112 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004113 bool changed = false;
4114 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004115
4116 if (status) {
4117 u8 mgmt_err = mgmt_status(status);
4118 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004119 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004120 return 0;
4121 }
4122
Johan Hedberg47990ea2012-02-22 11:58:37 +02004123 if (test_bit(HCI_AUTH, &hdev->flags)) {
4124 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4125 changed = true;
4126 } else {
4127 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4128 changed = true;
4129 }
4130
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004131 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004132 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004133
Johan Hedberg47990ea2012-02-22 11:58:37 +02004134 if (changed)
4135 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004136
4137 if (match.sk)
4138 sock_put(match.sk);
4139
4140 return err;
4141}
4142
Johan Hedberg890ea892013-03-15 17:06:52 -05004143static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004144{
Johan Hedberg890ea892013-03-15 17:06:52 -05004145 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004146 struct hci_cp_write_eir cp;
4147
Johan Hedberg976eb202012-10-24 21:12:01 +03004148 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004149 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004150
Johan Hedbergc80da272012-02-22 15:38:48 +02004151 memset(hdev->eir, 0, sizeof(hdev->eir));
4152
Johan Hedbergcacaf522012-02-21 00:52:42 +02004153 memset(&cp, 0, sizeof(cp));
4154
Johan Hedberg890ea892013-03-15 17:06:52 -05004155 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004156}
4157
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004158int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004159{
4160 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004161 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004162 bool changed = false;
4163 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004164
4165 if (status) {
4166 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004167
4168 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004169 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004170 err = new_settings(hdev, NULL);
4171
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004172 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4173 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004174
4175 return err;
4176 }
4177
4178 if (enable) {
4179 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4180 changed = true;
4181 } else {
4182 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4183 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004184 }
4185
4186 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4187
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004188 if (changed)
4189 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004190
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004191 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004192 sock_put(match.sk);
4193
Johan Hedberg890ea892013-03-15 17:06:52 -05004194 hci_req_init(&req, hdev);
4195
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004196 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004197 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004198 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004199 clear_eir(&req);
4200
4201 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004202
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004203 return err;
4204}
4205
Johan Hedberg92da6092013-03-15 17:06:55 -05004206static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004207{
4208 struct cmd_lookup *match = data;
4209
Johan Hedberg90e70452012-02-23 23:09:40 +02004210 if (match->sk == NULL) {
4211 match->sk = cmd->sk;
4212 sock_hold(match->sk);
4213 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004214}
4215
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004216int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004217 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004218{
Johan Hedberg90e70452012-02-23 23:09:40 +02004219 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4220 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004221
Johan Hedberg92da6092013-03-15 17:06:55 -05004222 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4223 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4224 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004225
4226 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004227 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4228 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004229
4230 if (match.sk)
4231 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004232
4233 return err;
4234}
4235
Johan Hedberg744cf192011-11-08 20:40:14 +02004236int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004237{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004238 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004239 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004240
Johan Hedberg13928972013-03-15 17:07:00 -05004241 if (status)
4242 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004243
4244 memset(&ev, 0, sizeof(ev));
4245 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004246 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004247
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004248 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004249 if (!cmd) {
4250 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004251
Johan Hedberg13928972013-03-15 17:07:00 -05004252 /* If this is a HCI command related to powering on the
4253 * HCI dev don't send any mgmt signals.
4254 */
4255 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4256 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004257 }
4258
Johan Hedberg13928972013-03-15 17:07:00 -05004259 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4260 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004261}
Szymon Jancc35938b2011-03-22 13:12:21 +01004262
Johan Hedberg744cf192011-11-08 20:40:14 +02004263int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004264 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004265{
4266 struct pending_cmd *cmd;
4267 int err;
4268
Johan Hedberg744cf192011-11-08 20:40:14 +02004269 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004270
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004271 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004272 if (!cmd)
4273 return -ENOENT;
4274
4275 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004276 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4277 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004278 } else {
4279 struct mgmt_rp_read_local_oob_data rp;
4280
4281 memcpy(rp.hash, hash, sizeof(rp.hash));
4282 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4283
Johan Hedberg744cf192011-11-08 20:40:14 +02004284 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004285 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4286 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004287 }
4288
4289 mgmt_pending_remove(cmd);
4290
4291 return err;
4292}
Johan Hedberge17acd42011-03-30 23:57:16 +03004293
Johan Hedberg48264f02011-11-09 13:58:58 +02004294int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004295 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4296 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004297{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004298 char buf[512];
4299 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004300 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004301
Andre Guedes12602d02013-04-30 15:29:40 -03004302 if (!hci_discovery_active(hdev))
4303 return -EPERM;
4304
Johan Hedberg1dc06092012-01-15 21:01:23 +02004305 /* Leave 5 bytes for a potential CoD field */
4306 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004307 return -EINVAL;
4308
Johan Hedberg1dc06092012-01-15 21:01:23 +02004309 memset(buf, 0, sizeof(buf));
4310
Johan Hedberge319d2e2012-01-15 19:51:59 +02004311 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004312 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004313 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004314 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304315 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004316 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304317 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004318
Johan Hedberg1dc06092012-01-15 21:01:23 +02004319 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004320 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004321
Johan Hedberg1dc06092012-01-15 21:01:23 +02004322 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4323 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004324 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004325
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004326 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004327 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004328
Johan Hedberge319d2e2012-01-15 19:51:59 +02004329 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004330}
Johan Hedberga88a9652011-03-30 13:18:12 +03004331
Johan Hedbergb644ba32012-01-17 21:48:47 +02004332int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004333 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004334{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004335 struct mgmt_ev_device_found *ev;
4336 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4337 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004338
Johan Hedbergb644ba32012-01-17 21:48:47 +02004339 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004340
Johan Hedbergb644ba32012-01-17 21:48:47 +02004341 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004342
Johan Hedbergb644ba32012-01-17 21:48:47 +02004343 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004344 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004345 ev->rssi = rssi;
4346
4347 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004348 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004349
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004350 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004351
Johan Hedberg053c7e02012-02-04 00:06:00 +02004352 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004353 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004354}
Johan Hedberg314b2382011-04-27 10:29:57 -04004355
Johan Hedberg744cf192011-11-08 20:40:14 +02004356int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004357{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004358 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004359 struct pending_cmd *cmd;
4360
Andre Guedes343fb142011-11-22 17:14:19 -03004361 BT_DBG("%s discovering %u", hdev->name, discovering);
4362
Johan Hedberg164a6e72011-11-01 17:06:44 +02004363 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004364 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004365 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004366 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004367
4368 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004369 u8 type = hdev->discovery.type;
4370
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004371 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4372 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004373 mgmt_pending_remove(cmd);
4374 }
4375
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004376 memset(&ev, 0, sizeof(ev));
4377 ev.type = hdev->discovery.type;
4378 ev.discovering = discovering;
4379
4380 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004381}
Antti Julku5e762442011-08-25 16:48:02 +03004382
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004383int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004384{
4385 struct pending_cmd *cmd;
4386 struct mgmt_ev_device_blocked ev;
4387
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004388 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004389
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004390 bacpy(&ev.addr.bdaddr, bdaddr);
4391 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004392
Johan Hedberg744cf192011-11-08 20:40:14 +02004393 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004394 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004395}
4396
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004397int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004398{
4399 struct pending_cmd *cmd;
4400 struct mgmt_ev_device_unblocked ev;
4401
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004402 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004403
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004404 bacpy(&ev.addr.bdaddr, bdaddr);
4405 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004406
Johan Hedberg744cf192011-11-08 20:40:14 +02004407 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004408 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004409}