blob: dcce0cf1d7ccada7bc1f0177c889ca4dac2f639d [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg2da9c552012-02-17 14:39:28 +020035#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060036#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020037
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070076 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030077 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030078 MGMT_OP_SET_BREDR,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800105#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200106
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200107#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
108 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
109
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200110struct pending_cmd {
111 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200112 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100114 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200115 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300116 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117};
118
Johan Hedbergca69b792011-11-11 18:10:00 +0200119/* HCI to MGMT error code conversion table */
120static u8 mgmt_status_table[] = {
121 MGMT_STATUS_SUCCESS,
122 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
123 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
124 MGMT_STATUS_FAILED, /* Hardware Failure */
125 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
126 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
127 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
128 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
129 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
130 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
132 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
133 MGMT_STATUS_BUSY, /* Command Disallowed */
134 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
135 MGMT_STATUS_REJECTED, /* Rejected Security */
136 MGMT_STATUS_REJECTED, /* Rejected Personal */
137 MGMT_STATUS_TIMEOUT, /* Host Timeout */
138 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
139 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
140 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
141 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
142 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
143 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
144 MGMT_STATUS_BUSY, /* Repeated Attempts */
145 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
146 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
147 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
148 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
149 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
150 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
151 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
152 MGMT_STATUS_FAILED, /* Unspecified Error */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
154 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
155 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
156 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
157 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
158 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
159 MGMT_STATUS_FAILED, /* Unit Link Key Used */
160 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
161 MGMT_STATUS_TIMEOUT, /* Instant Passed */
162 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
163 MGMT_STATUS_FAILED, /* Transaction Collision */
164 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
165 MGMT_STATUS_REJECTED, /* QoS Rejected */
166 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
167 MGMT_STATUS_REJECTED, /* Insufficient Security */
168 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
169 MGMT_STATUS_BUSY, /* Role Switch Pending */
170 MGMT_STATUS_FAILED, /* Slot Violation */
171 MGMT_STATUS_FAILED, /* Role Switch Failed */
172 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
173 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
174 MGMT_STATUS_BUSY, /* Host Busy Pairing */
175 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
176 MGMT_STATUS_BUSY, /* Controller Busy */
177 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
178 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
179 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
180 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
181 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
182};
183
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300184bool mgmt_valid_hdev(struct hci_dev *hdev)
185{
186 return hdev->dev_type == HCI_BREDR;
187}
188
Johan Hedbergca69b792011-11-11 18:10:00 +0200189static u8 mgmt_status(u8 hci_status)
190{
191 if (hci_status < ARRAY_SIZE(mgmt_status_table))
192 return mgmt_status_table[hci_status];
193
194 return MGMT_STATUS_FAILED;
195}
196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200198{
199 struct sk_buff *skb;
200 struct mgmt_hdr *hdr;
201 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300202 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Szymon Janc34eb5252011-02-28 14:10:08 +0100204 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205
Andre Guedes790eff42012-06-07 19:05:46 -0300206 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207 if (!skb)
208 return -ENOMEM;
209
210 hdr = (void *) skb_put(skb, sizeof(*hdr));
211
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530212 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100213 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214 hdr->len = cpu_to_le16(sizeof(*ev));
215
216 ev = (void *) skb_put(skb, sizeof(*ev));
217 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200218 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200219
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300220 err = sock_queue_rcv_skb(sk, skb);
221 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200222 kfree_skb(skb);
223
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300224 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200225}
226
Johan Hedbergaee9b212012-02-18 15:07:59 +0200227static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300228 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200229{
230 struct sk_buff *skb;
231 struct mgmt_hdr *hdr;
232 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200234
235 BT_DBG("sock %p", sk);
236
Andre Guedes790eff42012-06-07 19:05:46 -0300237 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200238 if (!skb)
239 return -ENOMEM;
240
241 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200242
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530243 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100244 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200248 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200249 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100250
251 if (rp)
252 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200253
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300254 err = sock_queue_rcv_skb(sk, skb);
255 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200256 kfree_skb(skb);
257
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100258 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200259}
260
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300261static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
262 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200263{
264 struct mgmt_rp_read_version rp;
265
266 BT_DBG("sock %p", sk);
267
268 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200269 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200270
Johan Hedbergaee9b212012-02-18 15:07:59 +0200271 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300272 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200273}
274
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300275static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
276 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200277{
278 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200279 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
280 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200281 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200282 size_t rp_size;
283 int i, err;
284
285 BT_DBG("sock %p", sk);
286
287 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
288
289 rp = kmalloc(rp_size, GFP_KERNEL);
290 if (!rp)
291 return -ENOMEM;
292
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200293 rp->num_commands = __constant_cpu_to_le16(num_commands);
294 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295
296 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
297 put_unaligned_le16(mgmt_commands[i], opcode);
298
299 for (i = 0; i < num_events; i++, opcode++)
300 put_unaligned_le16(mgmt_events[i], opcode);
301
Johan Hedbergaee9b212012-02-18 15:07:59 +0200302 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300303 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304 kfree(rp);
305
306 return err;
307}
308
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300309static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
310 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200313 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200314 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300316 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200317
318 BT_DBG("sock %p", sk);
319
320 read_lock(&hci_dev_list_lock);
321
322 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300323 list_for_each_entry(d, &hci_dev_list, list) {
324 if (!mgmt_valid_hdev(d))
325 continue;
326
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 count++;
328 }
329
Johan Hedberga38528f2011-01-22 06:46:43 +0200330 rp_len = sizeof(*rp) + (2 * count);
331 rp = kmalloc(rp_len, GFP_ATOMIC);
332 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100333 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200334 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100335 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200336
Johan Hedberg476e44c2012-10-19 20:10:46 +0300337 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200339 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200340 continue;
341
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700342 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
343 continue;
344
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300345 if (!mgmt_valid_hdev(d))
346 continue;
347
Johan Hedberg476e44c2012-10-19 20:10:46 +0300348 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 BT_DBG("Added hci%u", d->id);
350 }
351
Johan Hedberg476e44c2012-10-19 20:10:46 +0300352 rp->num_controllers = cpu_to_le16(count);
353 rp_len = sizeof(*rp) + (2 * count);
354
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b212012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Andre Guedes9a1a1992012-07-24 15:03:48 -0300372 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Andre Guedesed3fa312012-07-24 15:03:46 -0300375 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300376 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500377 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
378 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300379 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380 settings |= MGMT_SETTING_BREDR;
381 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100382 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700383 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300385 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200386 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300387 settings |= MGMT_SETTING_ADVERTISING;
388 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200389
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200390 return settings;
391}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200392
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200393static u32 get_current_settings(struct hci_dev *hdev)
394{
395 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200396
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200397 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 settings |= MGMT_SETTING_POWERED;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_CONNECTABLE;
402
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500403 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
404 settings |= MGMT_SETTING_FAST_CONNECTABLE;
405
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200406 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_DISCOVERABLE;
408
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200409 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_PAIRABLE;
411
Johan Hedberg56f87902013-10-02 13:43:13 +0300412 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_BREDR;
414
Johan Hedberg06199cf2012-02-22 16:37:11 +0200415 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200417
Johan Hedberg47990ea2012-02-22 11:58:37 +0200418 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200420
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200421 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200424 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
425 settings |= MGMT_SETTING_HS;
426
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300427 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
428 settings |= MGMT_SETTING_ADVERTISING;
429
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200430 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200431}
432
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300433#define PNP_INFO_SVCLASS_ID 0x1200
434
Johan Hedberg213202e2013-01-27 00:31:33 +0200435static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
436{
437 u8 *ptr = data, *uuids_start = NULL;
438 struct bt_uuid *uuid;
439
440 if (len < 4)
441 return ptr;
442
443 list_for_each_entry(uuid, &hdev->uuids, list) {
444 u16 uuid16;
445
446 if (uuid->size != 16)
447 continue;
448
449 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
450 if (uuid16 < 0x1100)
451 continue;
452
453 if (uuid16 == PNP_INFO_SVCLASS_ID)
454 continue;
455
456 if (!uuids_start) {
457 uuids_start = ptr;
458 uuids_start[0] = 1;
459 uuids_start[1] = EIR_UUID16_ALL;
460 ptr += 2;
461 }
462
463 /* Stop if not enough space to put next UUID */
464 if ((ptr - data) + sizeof(u16) > len) {
465 uuids_start[1] = EIR_UUID16_SOME;
466 break;
467 }
468
469 *ptr++ = (uuid16 & 0x00ff);
470 *ptr++ = (uuid16 & 0xff00) >> 8;
471 uuids_start[0] += sizeof(uuid16);
472 }
473
474 return ptr;
475}
476
Johan Hedbergcdf19632013-01-27 00:31:34 +0200477static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
478{
479 u8 *ptr = data, *uuids_start = NULL;
480 struct bt_uuid *uuid;
481
482 if (len < 6)
483 return ptr;
484
485 list_for_each_entry(uuid, &hdev->uuids, list) {
486 if (uuid->size != 32)
487 continue;
488
489 if (!uuids_start) {
490 uuids_start = ptr;
491 uuids_start[0] = 1;
492 uuids_start[1] = EIR_UUID32_ALL;
493 ptr += 2;
494 }
495
496 /* Stop if not enough space to put next UUID */
497 if ((ptr - data) + sizeof(u32) > len) {
498 uuids_start[1] = EIR_UUID32_SOME;
499 break;
500 }
501
502 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
503 ptr += sizeof(u32);
504 uuids_start[0] += sizeof(u32);
505 }
506
507 return ptr;
508}
509
Johan Hedbergc00d5752013-01-27 00:31:35 +0200510static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
511{
512 u8 *ptr = data, *uuids_start = NULL;
513 struct bt_uuid *uuid;
514
515 if (len < 18)
516 return ptr;
517
518 list_for_each_entry(uuid, &hdev->uuids, list) {
519 if (uuid->size != 128)
520 continue;
521
522 if (!uuids_start) {
523 uuids_start = ptr;
524 uuids_start[0] = 1;
525 uuids_start[1] = EIR_UUID128_ALL;
526 ptr += 2;
527 }
528
529 /* Stop if not enough space to put next UUID */
530 if ((ptr - data) + 16 > len) {
531 uuids_start[1] = EIR_UUID128_SOME;
532 break;
533 }
534
535 memcpy(ptr, uuid->uuid, 16);
536 ptr += 16;
537 uuids_start[0] += 16;
538 }
539
540 return ptr;
541}
542
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300543static void create_eir(struct hci_dev *hdev, u8 *data)
544{
545 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300546 size_t name_len;
547
548 name_len = strlen(hdev->dev_name);
549
550 if (name_len > 0) {
551 /* EIR Data type */
552 if (name_len > 48) {
553 name_len = 48;
554 ptr[1] = EIR_NAME_SHORT;
555 } else
556 ptr[1] = EIR_NAME_COMPLETE;
557
558 /* EIR Data length */
559 ptr[0] = name_len + 1;
560
561 memcpy(ptr + 2, hdev->dev_name, name_len);
562
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300563 ptr += (name_len + 2);
564 }
565
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100566 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700567 ptr[0] = 2;
568 ptr[1] = EIR_TX_POWER;
569 ptr[2] = (u8) hdev->inq_tx_power;
570
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700571 ptr += 3;
572 }
573
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700574 if (hdev->devid_source > 0) {
575 ptr[0] = 9;
576 ptr[1] = EIR_DEVICE_ID;
577
578 put_unaligned_le16(hdev->devid_source, ptr + 2);
579 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
580 put_unaligned_le16(hdev->devid_product, ptr + 6);
581 put_unaligned_le16(hdev->devid_version, ptr + 8);
582
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700583 ptr += 10;
584 }
585
Johan Hedberg213202e2013-01-27 00:31:33 +0200586 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200587 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200588 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300589}
590
Johan Hedberg890ea892013-03-15 17:06:52 -0500591static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300592{
Johan Hedberg890ea892013-03-15 17:06:52 -0500593 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300594 struct hci_cp_write_eir cp;
595
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200596 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500597 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200598
Johan Hedberg976eb202012-10-24 21:12:01 +0300599 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200602 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500603 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300604
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200605 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500606 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300607
608 memset(&cp, 0, sizeof(cp));
609
610 create_eir(hdev, cp.data);
611
612 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500613 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300614
615 memcpy(hdev->eir, cp.data, sizeof(cp.data));
616
Johan Hedberg890ea892013-03-15 17:06:52 -0500617 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300618}
619
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620static u8 get_service_classes(struct hci_dev *hdev)
621{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300622 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200623 u8 val = 0;
624
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300625 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200626 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627
628 return val;
629}
630
Johan Hedberg890ea892013-03-15 17:06:52 -0500631static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200632{
Johan Hedberg890ea892013-03-15 17:06:52 -0500633 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200634 u8 cod[3];
635
636 BT_DBG("%s", hdev->name);
637
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200638 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500639 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200640
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200641 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500642 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200643
644 cod[0] = hdev->minor_class;
645 cod[1] = hdev->major_class;
646 cod[2] = get_service_classes(hdev);
647
648 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500649 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200650
Johan Hedberg890ea892013-03-15 17:06:52 -0500651 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200652}
653
Johan Hedberg7d785252011-12-15 00:47:39 +0200654static void service_cache_off(struct work_struct *work)
655{
656 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300657 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500658 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200659
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200660 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200661 return;
662
Johan Hedberg890ea892013-03-15 17:06:52 -0500663 hci_req_init(&req, hdev);
664
Johan Hedberg7d785252011-12-15 00:47:39 +0200665 hci_dev_lock(hdev);
666
Johan Hedberg890ea892013-03-15 17:06:52 -0500667 update_eir(&req);
668 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200669
670 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500671
672 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200673}
674
Johan Hedberg6a919082012-02-28 06:17:26 +0200675static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200676{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200677 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200678 return;
679
Johan Hedberg4f87da82012-03-02 19:55:56 +0200680 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200681
Johan Hedberg4f87da82012-03-02 19:55:56 +0200682 /* Non-mgmt controlled devices get this bit set
683 * implicitly so that pairing works for them, however
684 * for mgmt we require user-space to explicitly enable
685 * it
686 */
687 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200688}
689
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200690static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300691 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200692{
693 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200694
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200695 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300697 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200698
Johan Hedberg03811012010-12-08 00:21:06 +0200699 memset(&rp, 0, sizeof(rp));
700
Johan Hedberg03811012010-12-08 00:21:06 +0200701 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200702
703 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200704 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200705
706 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
707 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
708
709 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200710
711 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200712 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200713
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300714 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200715
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200716 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300717 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200718}
719
720static void mgmt_pending_free(struct pending_cmd *cmd)
721{
722 sock_put(cmd->sk);
723 kfree(cmd->param);
724 kfree(cmd);
725}
726
727static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300728 struct hci_dev *hdev, void *data,
729 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200730{
731 struct pending_cmd *cmd;
732
Andre Guedes12b94562012-06-07 19:05:45 -0300733 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200734 if (!cmd)
735 return NULL;
736
737 cmd->opcode = opcode;
738 cmd->index = hdev->id;
739
Andre Guedes12b94562012-06-07 19:05:45 -0300740 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200741 if (!cmd->param) {
742 kfree(cmd);
743 return NULL;
744 }
745
746 if (data)
747 memcpy(cmd->param, data, len);
748
749 cmd->sk = sk;
750 sock_hold(sk);
751
752 list_add(&cmd->list, &hdev->mgmt_pending);
753
754 return cmd;
755}
756
757static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300758 void (*cb)(struct pending_cmd *cmd,
759 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300760 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200761{
Andre Guedesa3d09352013-02-01 11:21:30 -0300762 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200763
Andre Guedesa3d09352013-02-01 11:21:30 -0300764 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200765 if (opcode > 0 && cmd->opcode != opcode)
766 continue;
767
768 cb(cmd, data);
769 }
770}
771
772static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
773{
774 struct pending_cmd *cmd;
775
776 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
777 if (cmd->opcode == opcode)
778 return cmd;
779 }
780
781 return NULL;
782}
783
784static void mgmt_pending_remove(struct pending_cmd *cmd)
785{
786 list_del(&cmd->list);
787 mgmt_pending_free(cmd);
788}
789
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200790static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200791{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200792 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200793
Johan Hedbergaee9b212012-02-18 15:07:59 +0200794 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300795 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200796}
797
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200798static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300799 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200800{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300801 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200802 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200803 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200804
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200805 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200806
Johan Hedberga7e80f22013-01-09 16:05:19 +0200807 if (cp->val != 0x00 && cp->val != 0x01)
808 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
809 MGMT_STATUS_INVALID_PARAMS);
810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300811 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200812
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300813 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
814 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
815 MGMT_STATUS_BUSY);
816 goto failed;
817 }
818
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100819 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
820 cancel_delayed_work(&hdev->power_off);
821
822 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200823 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
824 data, len);
825 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100826 goto failed;
827 }
828 }
829
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200830 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200831 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200832 goto failed;
833 }
834
Johan Hedberg03811012010-12-08 00:21:06 +0200835 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
836 if (!cmd) {
837 err = -ENOMEM;
838 goto failed;
839 }
840
841 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200842 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200843 else
Johan Hedberg19202572013-01-14 22:33:51 +0200844 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200845
846 err = 0;
847
848failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300849 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200850 return err;
851}
852
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300853static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
854 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200855{
856 struct sk_buff *skb;
857 struct mgmt_hdr *hdr;
858
Andre Guedes790eff42012-06-07 19:05:46 -0300859 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200860 if (!skb)
861 return -ENOMEM;
862
863 hdr = (void *) skb_put(skb, sizeof(*hdr));
864 hdr->opcode = cpu_to_le16(event);
865 if (hdev)
866 hdr->index = cpu_to_le16(hdev->id);
867 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530868 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200869 hdr->len = cpu_to_le16(data_len);
870
871 if (data)
872 memcpy(skb_put(skb, data_len), data, data_len);
873
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100874 /* Time stamp */
875 __net_timestamp(skb);
876
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200877 hci_send_to_control(skb, skip_sk);
878 kfree_skb(skb);
879
880 return 0;
881}
882
883static int new_settings(struct hci_dev *hdev, struct sock *skip)
884{
885 __le32 ev;
886
887 ev = cpu_to_le32(get_current_settings(hdev));
888
889 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
890}
891
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300892struct cmd_lookup {
893 struct sock *sk;
894 struct hci_dev *hdev;
895 u8 mgmt_status;
896};
897
898static void settings_rsp(struct pending_cmd *cmd, void *data)
899{
900 struct cmd_lookup *match = data;
901
902 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
903
904 list_del(&cmd->list);
905
906 if (match->sk == NULL) {
907 match->sk = cmd->sk;
908 sock_hold(match->sk);
909 }
910
911 mgmt_pending_free(cmd);
912}
913
914static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
915{
916 u8 *status = data;
917
918 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
919 mgmt_pending_remove(cmd);
920}
921
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200922static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300923 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200924{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300925 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200926 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200927 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200928 u8 scan;
929 int err;
930
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200931 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200932
Johan Hedberg56f87902013-10-02 13:43:13 +0300933 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +0300934 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
935 MGMT_STATUS_NOT_SUPPORTED);
936
Johan Hedberga7e80f22013-01-09 16:05:19 +0200937 if (cp->val != 0x00 && cp->val != 0x01)
938 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
939 MGMT_STATUS_INVALID_PARAMS);
940
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700941 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100942 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200943 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300944 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200945
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300946 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200947
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200948 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200949 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300950 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200951 goto failed;
952 }
953
954 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300955 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200956 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300957 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200958 goto failed;
959 }
960
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200961 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200962 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300963 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200964 goto failed;
965 }
966
967 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200968 bool changed = false;
969
970 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
971 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
972 changed = true;
973 }
974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200976 if (err < 0)
977 goto failed;
978
979 if (changed)
980 err = new_settings(hdev, sk);
981
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 goto failed;
983 }
984
985 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100986 if (hdev->discov_timeout > 0) {
987 cancel_delayed_work(&hdev->discov_off);
988 hdev->discov_timeout = 0;
989 }
990
991 if (cp->val && timeout > 0) {
992 hdev->discov_timeout = timeout;
993 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
994 msecs_to_jiffies(hdev->discov_timeout * 1000));
995 }
996
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200997 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200998 goto failed;
999 }
1000
1001 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1002 if (!cmd) {
1003 err = -ENOMEM;
1004 goto failed;
1005 }
1006
1007 scan = SCAN_PAGE;
1008
1009 if (cp->val)
1010 scan |= SCAN_INQUIRY;
1011 else
1012 cancel_delayed_work(&hdev->discov_off);
1013
1014 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1015 if (err < 0)
1016 mgmt_pending_remove(cmd);
1017
Johan Hedberg03811012010-12-08 00:21:06 +02001018 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001019 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001020
1021failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001022 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001023 return err;
1024}
1025
Johan Hedberg406d7802013-03-15 17:07:09 -05001026static void write_fast_connectable(struct hci_request *req, bool enable)
1027{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001028 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001029 struct hci_cp_write_page_scan_activity acp;
1030 u8 type;
1031
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001032 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1033 return;
1034
Johan Hedberg406d7802013-03-15 17:07:09 -05001035 if (enable) {
1036 type = PAGE_SCAN_TYPE_INTERLACED;
1037
1038 /* 160 msec page scan interval */
1039 acp.interval = __constant_cpu_to_le16(0x0100);
1040 } else {
1041 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1042
1043 /* default 1.28 sec page scan */
1044 acp.interval = __constant_cpu_to_le16(0x0800);
1045 }
1046
1047 acp.window = __constant_cpu_to_le16(0x0012);
1048
Johan Hedbergbd98b992013-03-15 17:07:13 -05001049 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1050 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1051 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1052 sizeof(acp), &acp);
1053
1054 if (hdev->page_scan_type != type)
1055 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001056}
1057
Johan Hedberg2b76f452013-03-15 17:07:04 -05001058static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1059{
1060 struct pending_cmd *cmd;
1061
1062 BT_DBG("status 0x%02x", status);
1063
1064 hci_dev_lock(hdev);
1065
1066 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1067 if (!cmd)
1068 goto unlock;
1069
1070 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1071
1072 mgmt_pending_remove(cmd);
1073
1074unlock:
1075 hci_dev_unlock(hdev);
1076}
1077
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001078static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001079 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001080{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001081 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001082 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001083 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001084 u8 scan;
1085 int err;
1086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001087 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001088
Johan Hedberg56f87902013-10-02 13:43:13 +03001089 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001090 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1091 MGMT_STATUS_NOT_SUPPORTED);
1092
Johan Hedberga7e80f22013-01-09 16:05:19 +02001093 if (cp->val != 0x00 && cp->val != 0x01)
1094 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1095 MGMT_STATUS_INVALID_PARAMS);
1096
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001097 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001098
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001099 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001100 bool changed = false;
1101
1102 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1103 changed = true;
1104
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001105 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001106 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001107 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001108 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1109 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1110 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001111
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001112 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001113 if (err < 0)
1114 goto failed;
1115
1116 if (changed)
1117 err = new_settings(hdev, sk);
1118
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001119 goto failed;
1120 }
1121
1122 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001123 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001124 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001125 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001126 goto failed;
1127 }
1128
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001129 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001130 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001131 goto failed;
1132 }
1133
1134 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1135 if (!cmd) {
1136 err = -ENOMEM;
1137 goto failed;
1138 }
1139
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001140 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001141 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001142 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001143 scan = 0;
1144
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001145 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001146 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001147 cancel_delayed_work(&hdev->discov_off);
1148 }
1149
Johan Hedberg2b76f452013-03-15 17:07:04 -05001150 hci_req_init(&req, hdev);
1151
1152 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1153
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001154 /* If we're going from non-connectable to connectable or
1155 * vice-versa when fast connectable is enabled ensure that fast
1156 * connectable gets disabled. write_fast_connectable won't do
1157 * anything if the page scan parameters are already what they
1158 * should be.
1159 */
1160 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001161 write_fast_connectable(&req, false);
1162
Johan Hedberg2b76f452013-03-15 17:07:04 -05001163 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 if (err < 0)
1165 mgmt_pending_remove(cmd);
1166
1167failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001168 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001169 return err;
1170}
1171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001172static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001173 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001174{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001175 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001176 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001179
Johan Hedberga7e80f22013-01-09 16:05:19 +02001180 if (cp->val != 0x00 && cp->val != 0x01)
1181 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1182 MGMT_STATUS_INVALID_PARAMS);
1183
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001184 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001185
1186 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001187 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001188 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001189 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001190
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001191 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192 if (err < 0)
1193 goto failed;
1194
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001195 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196
1197failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001198 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001199 return err;
1200}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001201
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001202static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1203 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001204{
1205 struct mgmt_mode *cp = data;
1206 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001207 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001208 int err;
1209
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001210 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001211
Johan Hedberg56f87902013-10-02 13:43:13 +03001212 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001213 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1214 MGMT_STATUS_NOT_SUPPORTED);
1215
Johan Hedberga7e80f22013-01-09 16:05:19 +02001216 if (cp->val != 0x00 && cp->val != 0x01)
1217 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1218 MGMT_STATUS_INVALID_PARAMS);
1219
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001220 hci_dev_lock(hdev);
1221
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001222 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001223 bool changed = false;
1224
1225 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001226 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001227 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1228 changed = true;
1229 }
1230
1231 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1232 if (err < 0)
1233 goto failed;
1234
1235 if (changed)
1236 err = new_settings(hdev, sk);
1237
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001238 goto failed;
1239 }
1240
1241 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001242 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001243 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001244 goto failed;
1245 }
1246
1247 val = !!cp->val;
1248
1249 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1250 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1251 goto failed;
1252 }
1253
1254 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1255 if (!cmd) {
1256 err = -ENOMEM;
1257 goto failed;
1258 }
1259
1260 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1261 if (err < 0) {
1262 mgmt_pending_remove(cmd);
1263 goto failed;
1264 }
1265
1266failed:
1267 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001268 return err;
1269}
1270
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001271static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001272{
1273 struct mgmt_mode *cp = data;
1274 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001275 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001276 int err;
1277
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001278 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001279
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001280 if (!lmp_ssp_capable(hdev))
1281 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1282 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001283
Johan Hedberga7e80f22013-01-09 16:05:19 +02001284 if (cp->val != 0x00 && cp->val != 0x01)
1285 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1286 MGMT_STATUS_INVALID_PARAMS);
1287
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001288 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001289
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001290 val = !!cp->val;
1291
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001292 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001293 bool changed = false;
1294
1295 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1296 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1297 changed = true;
1298 }
1299
1300 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1301 if (err < 0)
1302 goto failed;
1303
1304 if (changed)
1305 err = new_settings(hdev, sk);
1306
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001307 goto failed;
1308 }
1309
1310 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001311 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1312 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001313 goto failed;
1314 }
1315
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001316 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1317 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1318 goto failed;
1319 }
1320
1321 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1322 if (!cmd) {
1323 err = -ENOMEM;
1324 goto failed;
1325 }
1326
1327 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1328 if (err < 0) {
1329 mgmt_pending_remove(cmd);
1330 goto failed;
1331 }
1332
1333failed:
1334 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001335 return err;
1336}
1337
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001338static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001339{
1340 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001341 bool changed;
1342 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001343
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001344 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001345
Johan Hedberg56f87902013-10-02 13:43:13 +03001346 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001347 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001348 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001349
Johan Hedberga7e80f22013-01-09 16:05:19 +02001350 if (cp->val != 0x00 && cp->val != 0x01)
1351 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1352 MGMT_STATUS_INVALID_PARAMS);
1353
Marcel Holtmannee392692013-10-01 22:59:23 -07001354 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001355
Marcel Holtmannee392692013-10-01 22:59:23 -07001356 if (cp->val)
1357 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1358 else
1359 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1360
1361 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1362 if (err < 0)
1363 goto unlock;
1364
1365 if (changed)
1366 err = new_settings(hdev, sk);
1367
1368unlock:
1369 hci_dev_unlock(hdev);
1370 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001371}
1372
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001373static void le_enable_complete(struct hci_dev *hdev, u8 status)
1374{
1375 struct cmd_lookup match = { NULL, hdev };
1376
1377 if (status) {
1378 u8 mgmt_err = mgmt_status(status);
1379
1380 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1381 &mgmt_err);
1382 return;
1383 }
1384
1385 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1386
1387 new_settings(hdev, match.sk);
1388
1389 if (match.sk)
1390 sock_put(match.sk);
1391}
1392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001394{
1395 struct mgmt_mode *cp = data;
1396 struct hci_cp_write_le_host_supported hci_cp;
1397 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001398 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001399 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001400 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001401
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001402 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001403
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001404 if (!lmp_le_capable(hdev))
1405 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1406 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001407
Johan Hedberga7e80f22013-01-09 16:05:19 +02001408 if (cp->val != 0x00 && cp->val != 0x01)
1409 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1410 MGMT_STATUS_INVALID_PARAMS);
1411
Johan Hedbergc73eee92013-04-19 18:35:21 +03001412 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001413 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001414 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1415 MGMT_STATUS_REJECTED);
1416
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001417 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001418
1419 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001420 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001421
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001422 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001423 bool changed = false;
1424
1425 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1426 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1427 changed = true;
1428 }
1429
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001430 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1431 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1432 changed = true;
1433 }
1434
Johan Hedberg06199cf2012-02-22 16:37:11 +02001435 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1436 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001437 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001438
1439 if (changed)
1440 err = new_settings(hdev, sk);
1441
Johan Hedberg1de028c2012-02-29 19:55:35 -08001442 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001443 }
1444
Johan Hedberg4375f102013-09-25 13:26:10 +03001445 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1446 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001447 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001448 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001449 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001450 }
1451
1452 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1453 if (!cmd) {
1454 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001455 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001456 }
1457
1458 memset(&hci_cp, 0, sizeof(hci_cp));
1459
1460 if (val) {
1461 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001462 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001463 }
1464
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001465 hci_req_init(&req, hdev);
1466
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001467 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1468 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1469
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001470 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1471 &hci_cp);
1472
1473 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301474 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001475 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001476
Johan Hedberg1de028c2012-02-29 19:55:35 -08001477unlock:
1478 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001479 return err;
1480}
1481
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001482/* This is a helper function to test for pending mgmt commands that can
1483 * cause CoD or EIR HCI commands. We can only allow one such pending
1484 * mgmt command at a time since otherwise we cannot easily track what
1485 * the current values are, will be, and based on that calculate if a new
1486 * HCI command needs to be sent and if yes with what value.
1487 */
1488static bool pending_eir_or_class(struct hci_dev *hdev)
1489{
1490 struct pending_cmd *cmd;
1491
1492 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1493 switch (cmd->opcode) {
1494 case MGMT_OP_ADD_UUID:
1495 case MGMT_OP_REMOVE_UUID:
1496 case MGMT_OP_SET_DEV_CLASS:
1497 case MGMT_OP_SET_POWERED:
1498 return true;
1499 }
1500 }
1501
1502 return false;
1503}
1504
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001505static const u8 bluetooth_base_uuid[] = {
1506 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1507 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1508};
1509
1510static u8 get_uuid_size(const u8 *uuid)
1511{
1512 u32 val;
1513
1514 if (memcmp(uuid, bluetooth_base_uuid, 12))
1515 return 128;
1516
1517 val = get_unaligned_le32(&uuid[12]);
1518 if (val > 0xffff)
1519 return 32;
1520
1521 return 16;
1522}
1523
Johan Hedberg92da6092013-03-15 17:06:55 -05001524static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1525{
1526 struct pending_cmd *cmd;
1527
1528 hci_dev_lock(hdev);
1529
1530 cmd = mgmt_pending_find(mgmt_op, hdev);
1531 if (!cmd)
1532 goto unlock;
1533
1534 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1535 hdev->dev_class, 3);
1536
1537 mgmt_pending_remove(cmd);
1538
1539unlock:
1540 hci_dev_unlock(hdev);
1541}
1542
1543static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1544{
1545 BT_DBG("status 0x%02x", status);
1546
1547 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1548}
1549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001550static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001551{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001552 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001553 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001554 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001555 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001556 int err;
1557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001558 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001559
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001560 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001561
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001562 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001563 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001564 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001565 goto failed;
1566 }
1567
Andre Guedes92c4c202012-06-07 19:05:44 -03001568 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001569 if (!uuid) {
1570 err = -ENOMEM;
1571 goto failed;
1572 }
1573
1574 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001575 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001576 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001577
Johan Hedbergde66aa62013-01-27 00:31:27 +02001578 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001579
Johan Hedberg890ea892013-03-15 17:06:52 -05001580 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001581
Johan Hedberg890ea892013-03-15 17:06:52 -05001582 update_class(&req);
1583 update_eir(&req);
1584
Johan Hedberg92da6092013-03-15 17:06:55 -05001585 err = hci_req_run(&req, add_uuid_complete);
1586 if (err < 0) {
1587 if (err != -ENODATA)
1588 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001589
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001591 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001592 goto failed;
1593 }
1594
1595 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001596 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001597 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001598 goto failed;
1599 }
1600
1601 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001602
1603failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001604 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001605 return err;
1606}
1607
Johan Hedberg24b78d02012-02-23 23:24:30 +02001608static bool enable_service_cache(struct hci_dev *hdev)
1609{
1610 if (!hdev_is_powered(hdev))
1611 return false;
1612
1613 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001614 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1615 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001616 return true;
1617 }
1618
1619 return false;
1620}
1621
Johan Hedberg92da6092013-03-15 17:06:55 -05001622static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1623{
1624 BT_DBG("status 0x%02x", status);
1625
1626 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1627}
1628
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001629static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001630 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001631{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001632 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001633 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001634 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001635 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 -05001636 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001637 int err, found;
1638
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001639 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001640
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001641 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001642
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001643 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001644 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001645 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001646 goto unlock;
1647 }
1648
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001649 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1650 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001651
Johan Hedberg24b78d02012-02-23 23:24:30 +02001652 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001653 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001654 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001655 goto unlock;
1656 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001657
Johan Hedberg9246a862012-02-23 21:33:16 +02001658 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001659 }
1660
1661 found = 0;
1662
Johan Hedberg056341c2013-01-27 00:31:30 +02001663 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001664 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1665 continue;
1666
1667 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001668 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001669 found++;
1670 }
1671
1672 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001673 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001674 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001675 goto unlock;
1676 }
1677
Johan Hedberg9246a862012-02-23 21:33:16 +02001678update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001679 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001680
Johan Hedberg890ea892013-03-15 17:06:52 -05001681 update_class(&req);
1682 update_eir(&req);
1683
Johan Hedberg92da6092013-03-15 17:06:55 -05001684 err = hci_req_run(&req, remove_uuid_complete);
1685 if (err < 0) {
1686 if (err != -ENODATA)
1687 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001688
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001689 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001690 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001691 goto unlock;
1692 }
1693
1694 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001695 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001696 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001697 goto unlock;
1698 }
1699
1700 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001701
1702unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001703 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001704 return err;
1705}
1706
Johan Hedberg92da6092013-03-15 17:06:55 -05001707static void set_class_complete(struct hci_dev *hdev, u8 status)
1708{
1709 BT_DBG("status 0x%02x", status);
1710
1711 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1712}
1713
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001714static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001715 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001716{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001717 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001718 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001719 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001720 int err;
1721
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001722 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001723
Johan Hedberg56f87902013-10-02 13:43:13 +03001724 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001725 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1726 MGMT_STATUS_NOT_SUPPORTED);
1727
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001728 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001729
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001730 if (pending_eir_or_class(hdev)) {
1731 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1732 MGMT_STATUS_BUSY);
1733 goto unlock;
1734 }
1735
1736 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1737 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1738 MGMT_STATUS_INVALID_PARAMS);
1739 goto unlock;
1740 }
1741
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001742 hdev->major_class = cp->major;
1743 hdev->minor_class = cp->minor;
1744
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001745 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001746 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001747 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001748 goto unlock;
1749 }
1750
Johan Hedberg890ea892013-03-15 17:06:52 -05001751 hci_req_init(&req, hdev);
1752
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001753 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001754 hci_dev_unlock(hdev);
1755 cancel_delayed_work_sync(&hdev->service_cache);
1756 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001757 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001758 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001759
Johan Hedberg890ea892013-03-15 17:06:52 -05001760 update_class(&req);
1761
Johan Hedberg92da6092013-03-15 17:06:55 -05001762 err = hci_req_run(&req, set_class_complete);
1763 if (err < 0) {
1764 if (err != -ENODATA)
1765 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001768 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001769 goto unlock;
1770 }
1771
1772 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001773 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001774 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001775 goto unlock;
1776 }
1777
1778 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001779
Johan Hedbergb5235a62012-02-21 14:32:24 +02001780unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001781 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001782 return err;
1783}
1784
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001785static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001786 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001787{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001788 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001789 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001790 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001791
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001792 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001793
Johan Hedberg86742e12011-11-07 23:13:38 +02001794 expected_len = sizeof(*cp) + key_count *
1795 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001796 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001797 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001798 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001799 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001800 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001801 }
1802
Johan Hedberg4ae14302013-01-20 14:27:13 +02001803 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1804 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1805 MGMT_STATUS_INVALID_PARAMS);
1806
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001807 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001808 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001809
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001810 for (i = 0; i < key_count; i++) {
1811 struct mgmt_link_key_info *key = &cp->keys[i];
1812
1813 if (key->addr.type != BDADDR_BREDR)
1814 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1815 MGMT_STATUS_INVALID_PARAMS);
1816 }
1817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001818 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001819
1820 hci_link_keys_clear(hdev);
1821
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001822 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001823 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001824 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001825 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001826
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001827 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001828 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001829
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001830 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001831 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001832 }
1833
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001834 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001835
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001836 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001837
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001838 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001839}
1840
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001841static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001843{
1844 struct mgmt_ev_device_unpaired ev;
1845
1846 bacpy(&ev.addr.bdaddr, bdaddr);
1847 ev.addr.type = addr_type;
1848
1849 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001850 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001851}
1852
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001853static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001854 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001855{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001856 struct mgmt_cp_unpair_device *cp = data;
1857 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001858 struct hci_cp_disconnect dc;
1859 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001860 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001861 int err;
1862
Johan Hedberga8a1d192011-11-10 15:54:38 +02001863 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001864 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1865 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001866
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001867 if (!bdaddr_type_is_valid(cp->addr.type))
1868 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1869 MGMT_STATUS_INVALID_PARAMS,
1870 &rp, sizeof(rp));
1871
Johan Hedberg118da702013-01-20 14:27:20 +02001872 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1873 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1874 MGMT_STATUS_INVALID_PARAMS,
1875 &rp, sizeof(rp));
1876
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001877 hci_dev_lock(hdev);
1878
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001879 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001880 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001881 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001882 goto unlock;
1883 }
1884
Andre Guedes591f47f2012-04-24 21:02:49 -03001885 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001886 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1887 else
1888 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001889
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001890 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001891 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001892 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001893 goto unlock;
1894 }
1895
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001896 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001897 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001898 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001899 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001900 else
1901 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001902 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001903 } else {
1904 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001905 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001906
Johan Hedberga8a1d192011-11-10 15:54:38 +02001907 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001908 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001909 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001910 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001911 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001912 }
1913
Johan Hedberg124f6e32012-02-09 13:50:12 +02001914 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001915 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001916 if (!cmd) {
1917 err = -ENOMEM;
1918 goto unlock;
1919 }
1920
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001921 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001922 dc.reason = 0x13; /* Remote User Terminated Connection */
1923 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1924 if (err < 0)
1925 mgmt_pending_remove(cmd);
1926
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001927unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001928 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001929 return err;
1930}
1931
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001932static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001933 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001934{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001935 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001936 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001937 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001938 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001939 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001940 int err;
1941
1942 BT_DBG("");
1943
Johan Hedberg06a63b12013-01-20 14:27:21 +02001944 memset(&rp, 0, sizeof(rp));
1945 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1946 rp.addr.type = cp->addr.type;
1947
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001948 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001949 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1950 MGMT_STATUS_INVALID_PARAMS,
1951 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001952
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001953 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001954
1955 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001956 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1957 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001958 goto failed;
1959 }
1960
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001961 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001962 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1963 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001964 goto failed;
1965 }
1966
Andre Guedes591f47f2012-04-24 21:02:49 -03001967 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001968 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1969 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001970 else
1971 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001972
Vishal Agarwalf9607272012-06-13 05:32:43 +05301973 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001974 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1975 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001976 goto failed;
1977 }
1978
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001979 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001980 if (!cmd) {
1981 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001982 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001983 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001984
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001985 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001986 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001987
1988 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1989 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001990 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001991
1992failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001993 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001994 return err;
1995}
1996
Andre Guedes57c14772012-04-24 21:02:50 -03001997static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001998{
1999 switch (link_type) {
2000 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002001 switch (addr_type) {
2002 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002003 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002004
Johan Hedberg48264f02011-11-09 13:58:58 +02002005 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002006 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002007 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002008 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002009
Johan Hedberg4c659c32011-11-07 23:13:39 +02002010 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002011 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002012 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002013 }
2014}
2015
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002016static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2017 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002018{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002019 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002020 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002021 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002022 int err;
2023 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002024
2025 BT_DBG("");
2026
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002027 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002028
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002029 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002030 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002031 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002032 goto unlock;
2033 }
2034
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002035 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002036 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2037 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002038 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002039 }
2040
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002041 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002042 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002043 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002044 err = -ENOMEM;
2045 goto unlock;
2046 }
2047
Johan Hedberg2784eb42011-01-21 13:56:35 +02002048 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002049 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002050 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2051 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002052 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002053 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002054 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002055 continue;
2056 i++;
2057 }
2058
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002059 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002060
Johan Hedberg4c659c32011-11-07 23:13:39 +02002061 /* Recalculate length in case of filtered SCO connections, etc */
2062 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002064 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002065 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002066
Johan Hedberga38528f2011-01-22 06:46:43 +02002067 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002068
2069unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002070 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002071 return err;
2072}
2073
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002074static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002075 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002076{
2077 struct pending_cmd *cmd;
2078 int err;
2079
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002080 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002081 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002082 if (!cmd)
2083 return -ENOMEM;
2084
Johan Hedbergd8457692012-02-17 14:24:57 +02002085 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002086 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002087 if (err < 0)
2088 mgmt_pending_remove(cmd);
2089
2090 return err;
2091}
2092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002093static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002094 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002095{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002096 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002097 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002098 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002099 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002100 int err;
2101
2102 BT_DBG("");
2103
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002104 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002105
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002106 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002107 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002108 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002109 goto failed;
2110 }
2111
Johan Hedbergd8457692012-02-17 14:24:57 +02002112 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002113 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002116 goto failed;
2117 }
2118
2119 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002120 struct mgmt_cp_pin_code_neg_reply ncp;
2121
2122 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002123
2124 BT_ERR("PIN code is not 16 bytes long");
2125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002126 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002127 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002128 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002129 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002130
2131 goto failed;
2132 }
2133
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002134 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002135 if (!cmd) {
2136 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002137 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002138 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002139
Johan Hedbergd8457692012-02-17 14:24:57 +02002140 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002141 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002142 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002143
2144 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2145 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002146 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002147
2148failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002149 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002150 return err;
2151}
2152
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002153static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2154 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002155{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002156 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002157
2158 BT_DBG("");
2159
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002160 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002161
2162 hdev->io_capability = cp->io_capability;
2163
2164 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002165 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002166
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002167 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002168
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002169 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2170 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002171}
2172
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002173static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002174{
2175 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002176 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002177
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002178 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002179 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2180 continue;
2181
Johan Hedberge9a416b2011-02-19 12:05:56 -03002182 if (cmd->user_data != conn)
2183 continue;
2184
2185 return cmd;
2186 }
2187
2188 return NULL;
2189}
2190
2191static void pairing_complete(struct pending_cmd *cmd, u8 status)
2192{
2193 struct mgmt_rp_pair_device rp;
2194 struct hci_conn *conn = cmd->user_data;
2195
Johan Hedbergba4e5642011-11-11 00:07:34 +02002196 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002197 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002198
Johan Hedbergaee9b212012-02-18 15:07:59 +02002199 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002200 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002201
2202 /* So we don't get further callbacks for this connection */
2203 conn->connect_cfm_cb = NULL;
2204 conn->security_cfm_cb = NULL;
2205 conn->disconn_cfm_cb = NULL;
2206
David Herrmann76a68ba2013-04-06 20:28:37 +02002207 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002208
Johan Hedberga664b5b2011-02-19 12:06:02 -03002209 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002210}
2211
2212static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2213{
2214 struct pending_cmd *cmd;
2215
2216 BT_DBG("status %u", status);
2217
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002218 cmd = find_pairing(conn);
2219 if (!cmd)
2220 BT_DBG("Unable to find a pending command");
2221 else
Johan Hedberge2113262012-02-18 15:20:03 +02002222 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002223}
2224
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302225static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2226{
2227 struct pending_cmd *cmd;
2228
2229 BT_DBG("status %u", status);
2230
2231 if (!status)
2232 return;
2233
2234 cmd = find_pairing(conn);
2235 if (!cmd)
2236 BT_DBG("Unable to find a pending command");
2237 else
2238 pairing_complete(cmd, mgmt_status(status));
2239}
2240
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002241static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002242 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002243{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002244 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002245 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002246 struct pending_cmd *cmd;
2247 u8 sec_level, auth_type;
2248 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002249 int err;
2250
2251 BT_DBG("");
2252
Szymon Jancf950a30e2013-01-18 12:48:07 +01002253 memset(&rp, 0, sizeof(rp));
2254 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2255 rp.addr.type = cp->addr.type;
2256
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002257 if (!bdaddr_type_is_valid(cp->addr.type))
2258 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2259 MGMT_STATUS_INVALID_PARAMS,
2260 &rp, sizeof(rp));
2261
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002262 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002263
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002264 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002265 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2266 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002267 goto unlock;
2268 }
2269
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002270 sec_level = BT_SECURITY_MEDIUM;
2271 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002272 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002273 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002274 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002275
Andre Guedes591f47f2012-04-24 21:02:49 -03002276 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002277 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2278 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002279 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002280 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2281 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002282
Ville Tervo30e76272011-02-22 16:10:53 -03002283 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002284 int status;
2285
2286 if (PTR_ERR(conn) == -EBUSY)
2287 status = MGMT_STATUS_BUSY;
2288 else
2289 status = MGMT_STATUS_CONNECT_FAILED;
2290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002291 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002292 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002293 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002294 goto unlock;
2295 }
2296
2297 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002298 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002299 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002300 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002301 goto unlock;
2302 }
2303
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002304 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305 if (!cmd) {
2306 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002307 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002308 goto unlock;
2309 }
2310
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002311 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002312 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002313 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302314 else
2315 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002316
Johan Hedberge9a416b2011-02-19 12:05:56 -03002317 conn->security_cfm_cb = pairing_complete_cb;
2318 conn->disconn_cfm_cb = pairing_complete_cb;
2319 conn->io_capability = cp->io_cap;
2320 cmd->user_data = conn;
2321
2322 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002323 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002324 pairing_complete(cmd, 0);
2325
2326 err = 0;
2327
2328unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002329 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002330 return err;
2331}
2332
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002333static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2334 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002335{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002336 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002337 struct pending_cmd *cmd;
2338 struct hci_conn *conn;
2339 int err;
2340
2341 BT_DBG("");
2342
Johan Hedberg28424702012-02-02 04:02:29 +02002343 hci_dev_lock(hdev);
2344
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002345 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002346 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002347 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002348 goto unlock;
2349 }
2350
Johan Hedberg28424702012-02-02 04:02:29 +02002351 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2352 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002353 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002354 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002355 goto unlock;
2356 }
2357
2358 conn = cmd->user_data;
2359
2360 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002361 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002362 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002363 goto unlock;
2364 }
2365
2366 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2367
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002368 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002369 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002370unlock:
2371 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002372 return err;
2373}
2374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002375static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002376 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002377 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002378{
Johan Hedberga5c29682011-02-19 12:05:57 -03002379 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002380 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002381 int err;
2382
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002383 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002384
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002385 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002386 err = cmd_complete(sk, hdev->id, mgmt_op,
2387 MGMT_STATUS_NOT_POWERED, addr,
2388 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002389 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002390 }
2391
Johan Hedberg1707c602013-03-15 17:07:15 -05002392 if (addr->type == BDADDR_BREDR)
2393 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002394 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002395 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002396
Johan Hedberg272d90d2012-02-09 15:26:12 +02002397 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002398 err = cmd_complete(sk, hdev->id, mgmt_op,
2399 MGMT_STATUS_NOT_CONNECTED, addr,
2400 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002401 goto done;
2402 }
2403
Johan Hedberg1707c602013-03-15 17:07:15 -05002404 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002405 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002406 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002407
Brian Gix5fe57d92011-12-21 16:12:13 -08002408 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002409 err = cmd_complete(sk, hdev->id, mgmt_op,
2410 MGMT_STATUS_SUCCESS, addr,
2411 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002412 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002413 err = cmd_complete(sk, hdev->id, mgmt_op,
2414 MGMT_STATUS_FAILED, addr,
2415 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002416
Brian Gix47c15e22011-11-16 13:53:14 -08002417 goto done;
2418 }
2419
Johan Hedberg1707c602013-03-15 17:07:15 -05002420 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002421 if (!cmd) {
2422 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002423 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002424 }
2425
Brian Gix0df4c182011-11-16 13:53:13 -08002426 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002427 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2428 struct hci_cp_user_passkey_reply cp;
2429
Johan Hedberg1707c602013-03-15 17:07:15 -05002430 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002431 cp.passkey = passkey;
2432 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2433 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002434 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2435 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002436
Johan Hedberga664b5b2011-02-19 12:06:02 -03002437 if (err < 0)
2438 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002439
Brian Gix0df4c182011-11-16 13:53:13 -08002440done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002441 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002442 return err;
2443}
2444
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302445static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2446 void *data, u16 len)
2447{
2448 struct mgmt_cp_pin_code_neg_reply *cp = data;
2449
2450 BT_DBG("");
2451
Johan Hedberg1707c602013-03-15 17:07:15 -05002452 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302453 MGMT_OP_PIN_CODE_NEG_REPLY,
2454 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2455}
2456
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002457static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2458 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002459{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002460 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002461
2462 BT_DBG("");
2463
2464 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002465 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002466 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002467
Johan Hedberg1707c602013-03-15 17:07:15 -05002468 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002469 MGMT_OP_USER_CONFIRM_REPLY,
2470 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002471}
2472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002473static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002474 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002475{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002476 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002477
2478 BT_DBG("");
2479
Johan Hedberg1707c602013-03-15 17:07:15 -05002480 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002481 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2482 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002483}
2484
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002485static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2486 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002487{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002488 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002489
2490 BT_DBG("");
2491
Johan Hedberg1707c602013-03-15 17:07:15 -05002492 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002493 MGMT_OP_USER_PASSKEY_REPLY,
2494 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002495}
2496
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002497static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002498 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002499{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002500 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002501
2502 BT_DBG("");
2503
Johan Hedberg1707c602013-03-15 17:07:15 -05002504 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002505 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2506 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002507}
2508
Johan Hedberg13928972013-03-15 17:07:00 -05002509static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002510{
Johan Hedberg13928972013-03-15 17:07:00 -05002511 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002512 struct hci_cp_write_local_name cp;
2513
Johan Hedberg13928972013-03-15 17:07:00 -05002514 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002515
Johan Hedberg890ea892013-03-15 17:06:52 -05002516 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002517}
2518
Johan Hedberg13928972013-03-15 17:07:00 -05002519static void set_name_complete(struct hci_dev *hdev, u8 status)
2520{
2521 struct mgmt_cp_set_local_name *cp;
2522 struct pending_cmd *cmd;
2523
2524 BT_DBG("status 0x%02x", status);
2525
2526 hci_dev_lock(hdev);
2527
2528 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2529 if (!cmd)
2530 goto unlock;
2531
2532 cp = cmd->param;
2533
2534 if (status)
2535 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2536 mgmt_status(status));
2537 else
2538 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2539 cp, sizeof(*cp));
2540
2541 mgmt_pending_remove(cmd);
2542
2543unlock:
2544 hci_dev_unlock(hdev);
2545}
2546
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002547static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002548 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002549{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002550 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002551 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002552 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002553 int err;
2554
2555 BT_DBG("");
2556
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002557 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002558
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002559 /* If the old values are the same as the new ones just return a
2560 * direct command complete event.
2561 */
2562 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2563 !memcmp(hdev->short_name, cp->short_name,
2564 sizeof(hdev->short_name))) {
2565 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2566 data, len);
2567 goto failed;
2568 }
2569
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002570 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002571
Johan Hedbergb5235a62012-02-21 14:32:24 +02002572 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002573 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002574
2575 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002576 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002577 if (err < 0)
2578 goto failed;
2579
2580 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002581 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002582
Johan Hedbergb5235a62012-02-21 14:32:24 +02002583 goto failed;
2584 }
2585
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002586 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002587 if (!cmd) {
2588 err = -ENOMEM;
2589 goto failed;
2590 }
2591
Johan Hedberg13928972013-03-15 17:07:00 -05002592 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2593
Johan Hedberg890ea892013-03-15 17:06:52 -05002594 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002595
2596 if (lmp_bredr_capable(hdev)) {
2597 update_name(&req);
2598 update_eir(&req);
2599 }
2600
2601 if (lmp_le_capable(hdev))
2602 hci_update_ad(&req);
2603
Johan Hedberg13928972013-03-15 17:07:00 -05002604 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002605 if (err < 0)
2606 mgmt_pending_remove(cmd);
2607
2608failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002609 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002610 return err;
2611}
2612
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002613static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002614 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002615{
Szymon Jancc35938b2011-03-22 13:12:21 +01002616 struct pending_cmd *cmd;
2617 int err;
2618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002619 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002620
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002621 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002622
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002623 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002624 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002625 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002626 goto unlock;
2627 }
2628
Andre Guedes9a1a1992012-07-24 15:03:48 -03002629 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002630 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002631 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002632 goto unlock;
2633 }
2634
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002635 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002636 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002637 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002638 goto unlock;
2639 }
2640
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002641 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002642 if (!cmd) {
2643 err = -ENOMEM;
2644 goto unlock;
2645 }
2646
2647 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2648 if (err < 0)
2649 mgmt_pending_remove(cmd);
2650
2651unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002652 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002653 return err;
2654}
2655
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002656static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002657 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002658{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002659 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002660 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002661 int err;
2662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002663 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002665 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002666
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002667 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002668 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002669 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002670 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002671 else
Szymon Janca6785be2012-12-13 15:11:21 +01002672 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002673
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002674 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002675 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002676
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002677 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002678 return err;
2679}
2680
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002681static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002682 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002683{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002684 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002685 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002686 int err;
2687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002688 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002690 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002691
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002692 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002693 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002694 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002695 else
Szymon Janca6785be2012-12-13 15:11:21 +01002696 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002700
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002701 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002702 return err;
2703}
2704
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002705static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2706{
2707 struct pending_cmd *cmd;
2708 u8 type;
2709 int err;
2710
2711 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2712
2713 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2714 if (!cmd)
2715 return -ENOENT;
2716
2717 type = hdev->discovery.type;
2718
2719 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2720 &type, sizeof(type));
2721 mgmt_pending_remove(cmd);
2722
2723 return err;
2724}
2725
Andre Guedes7c307722013-04-30 15:29:28 -03002726static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2727{
2728 BT_DBG("status %d", status);
2729
2730 if (status) {
2731 hci_dev_lock(hdev);
2732 mgmt_start_discovery_failed(hdev, status);
2733 hci_dev_unlock(hdev);
2734 return;
2735 }
2736
2737 hci_dev_lock(hdev);
2738 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2739 hci_dev_unlock(hdev);
2740
2741 switch (hdev->discovery.type) {
2742 case DISCOV_TYPE_LE:
2743 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002744 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002745 break;
2746
2747 case DISCOV_TYPE_INTERLEAVED:
2748 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002749 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002750 break;
2751
2752 case DISCOV_TYPE_BREDR:
2753 break;
2754
2755 default:
2756 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2757 }
2758}
2759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002762{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002763 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002764 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002765 struct hci_cp_le_set_scan_param param_cp;
2766 struct hci_cp_le_set_scan_enable enable_cp;
2767 struct hci_cp_inquiry inq_cp;
2768 struct hci_request req;
2769 /* General inquiry access code (GIAC) */
2770 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002771 int err;
2772
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002773 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002774
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002775 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002776
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002777 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002778 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002779 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002780 goto failed;
2781 }
2782
Andre Guedes642be6c2012-03-21 00:03:37 -03002783 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2784 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2785 MGMT_STATUS_BUSY);
2786 goto failed;
2787 }
2788
Johan Hedbergff9ef572012-01-04 14:23:45 +02002789 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002790 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002791 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002792 goto failed;
2793 }
2794
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002795 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002796 if (!cmd) {
2797 err = -ENOMEM;
2798 goto failed;
2799 }
2800
Andre Guedes4aab14e2012-02-17 20:39:36 -03002801 hdev->discovery.type = cp->type;
2802
Andre Guedes7c307722013-04-30 15:29:28 -03002803 hci_req_init(&req, hdev);
2804
Andre Guedes4aab14e2012-02-17 20:39:36 -03002805 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002806 case DISCOV_TYPE_BREDR:
Johan Hedberg56f87902013-10-02 13:43:13 +03002807 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002808 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2809 MGMT_STATUS_NOT_SUPPORTED);
2810 mgmt_pending_remove(cmd);
2811 goto failed;
2812 }
2813
Andre Guedes7c307722013-04-30 15:29:28 -03002814 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2815 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2816 MGMT_STATUS_BUSY);
2817 mgmt_pending_remove(cmd);
2818 goto failed;
2819 }
2820
2821 hci_inquiry_cache_flush(hdev);
2822
2823 memset(&inq_cp, 0, sizeof(inq_cp));
2824 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002825 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002826 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002827 break;
2828
2829 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002830 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002831 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002832 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2833 MGMT_STATUS_NOT_SUPPORTED);
2834 mgmt_pending_remove(cmd);
2835 goto failed;
2836 }
2837
Andre Guedes7c307722013-04-30 15:29:28 -03002838 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002839 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002840 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2841 MGMT_STATUS_NOT_SUPPORTED);
2842 mgmt_pending_remove(cmd);
2843 goto failed;
2844 }
2845
Andre Guedes7c307722013-04-30 15:29:28 -03002846 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2847 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2848 MGMT_STATUS_REJECTED);
2849 mgmt_pending_remove(cmd);
2850 goto failed;
2851 }
2852
2853 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2854 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2855 MGMT_STATUS_BUSY);
2856 mgmt_pending_remove(cmd);
2857 goto failed;
2858 }
2859
2860 memset(&param_cp, 0, sizeof(param_cp));
2861 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002862 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2863 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002864 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2865 &param_cp);
2866
2867 memset(&enable_cp, 0, sizeof(enable_cp));
2868 enable_cp.enable = LE_SCAN_ENABLE;
2869 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2870 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2871 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002872 break;
2873
Andre Guedesf39799f2012-02-17 20:39:35 -03002874 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002875 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2876 MGMT_STATUS_INVALID_PARAMS);
2877 mgmt_pending_remove(cmd);
2878 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002879 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002880
Andre Guedes7c307722013-04-30 15:29:28 -03002881 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002882 if (err < 0)
2883 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002884 else
2885 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002886
2887failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002888 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002889 return err;
2890}
2891
Andre Guedes1183fdc2013-04-30 15:29:35 -03002892static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2893{
2894 struct pending_cmd *cmd;
2895 int err;
2896
2897 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2898 if (!cmd)
2899 return -ENOENT;
2900
2901 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2902 &hdev->discovery.type, sizeof(hdev->discovery.type));
2903 mgmt_pending_remove(cmd);
2904
2905 return err;
2906}
2907
Andre Guedes0e05bba2013-04-30 15:29:33 -03002908static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2909{
2910 BT_DBG("status %d", status);
2911
2912 hci_dev_lock(hdev);
2913
2914 if (status) {
2915 mgmt_stop_discovery_failed(hdev, status);
2916 goto unlock;
2917 }
2918
2919 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2920
2921unlock:
2922 hci_dev_unlock(hdev);
2923}
2924
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002925static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002926 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002927{
Johan Hedbergd9306502012-02-20 23:25:18 +02002928 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002929 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002930 struct hci_cp_remote_name_req_cancel cp;
2931 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002932 struct hci_request req;
2933 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002934 int err;
2935
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002936 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002938 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002939
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002940 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002941 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002942 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2943 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002944 goto unlock;
2945 }
2946
2947 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002948 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002949 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2950 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002951 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002952 }
2953
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002954 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002955 if (!cmd) {
2956 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002957 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002958 }
2959
Andre Guedes0e05bba2013-04-30 15:29:33 -03002960 hci_req_init(&req, hdev);
2961
Andre Guedese0d9727e2012-03-20 15:15:36 -03002962 switch (hdev->discovery.state) {
2963 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002964 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2965 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2966 } else {
2967 cancel_delayed_work(&hdev->le_scan_disable);
2968
2969 memset(&enable_cp, 0, sizeof(enable_cp));
2970 enable_cp.enable = LE_SCAN_DISABLE;
2971 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2972 sizeof(enable_cp), &enable_cp);
2973 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002974
Andre Guedese0d9727e2012-03-20 15:15:36 -03002975 break;
2976
2977 case DISCOVERY_RESOLVING:
2978 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002979 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002980 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002981 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002982 err = cmd_complete(sk, hdev->id,
2983 MGMT_OP_STOP_DISCOVERY, 0,
2984 &mgmt_cp->type,
2985 sizeof(mgmt_cp->type));
2986 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2987 goto unlock;
2988 }
2989
2990 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002991 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2992 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002993
2994 break;
2995
2996 default:
2997 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002998
2999 mgmt_pending_remove(cmd);
3000 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3001 MGMT_STATUS_FAILED, &mgmt_cp->type,
3002 sizeof(mgmt_cp->type));
3003 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003004 }
3005
Andre Guedes0e05bba2013-04-30 15:29:33 -03003006 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003007 if (err < 0)
3008 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003009 else
3010 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003011
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003012unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003013 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003014 return err;
3015}
3016
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003017static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003019{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003020 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003021 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003022 int err;
3023
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003024 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003025
Johan Hedberg561aafb2012-01-04 13:31:59 +02003026 hci_dev_lock(hdev);
3027
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003028 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003029 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003030 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003031 goto failed;
3032 }
3033
Johan Hedberga198e7b2012-02-17 14:27:06 +02003034 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003035 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003036 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003037 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003038 goto failed;
3039 }
3040
3041 if (cp->name_known) {
3042 e->name_state = NAME_KNOWN;
3043 list_del(&e->list);
3044 } else {
3045 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003046 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003047 }
3048
Johan Hedberge3846622013-01-09 15:29:33 +02003049 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3050 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003051
3052failed:
3053 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003054 return err;
3055}
3056
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003057static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003058 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003059{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003060 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003061 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003062 int err;
3063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003064 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003065
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003066 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003067 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3068 MGMT_STATUS_INVALID_PARAMS,
3069 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003070
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003071 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003072
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003073 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003074 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003075 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003076 else
Szymon Janca6785be2012-12-13 15:11:21 +01003077 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003078
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003079 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003080 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003081
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003082 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003083
3084 return err;
3085}
3086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003087static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003088 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003089{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003090 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003091 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003092 int err;
3093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003094 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003095
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003096 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003097 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3098 MGMT_STATUS_INVALID_PARAMS,
3099 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003100
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003101 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003102
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003103 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003104 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003105 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003106 else
Szymon Janca6785be2012-12-13 15:11:21 +01003107 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003109 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003110 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003112 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003113
3114 return err;
3115}
3116
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003117static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3118 u16 len)
3119{
3120 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003121 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003122 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003123 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003124
3125 BT_DBG("%s", hdev->name);
3126
Szymon Jancc72d4b82012-03-16 16:02:57 +01003127 source = __le16_to_cpu(cp->source);
3128
3129 if (source > 0x0002)
3130 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3131 MGMT_STATUS_INVALID_PARAMS);
3132
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003133 hci_dev_lock(hdev);
3134
Szymon Jancc72d4b82012-03-16 16:02:57 +01003135 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003136 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3137 hdev->devid_product = __le16_to_cpu(cp->product);
3138 hdev->devid_version = __le16_to_cpu(cp->version);
3139
3140 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3141
Johan Hedberg890ea892013-03-15 17:06:52 -05003142 hci_req_init(&req, hdev);
3143 update_eir(&req);
3144 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003145
3146 hci_dev_unlock(hdev);
3147
3148 return err;
3149}
3150
Johan Hedberg4375f102013-09-25 13:26:10 +03003151static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3152{
3153 struct cmd_lookup match = { NULL, hdev };
3154
3155 if (status) {
3156 u8 mgmt_err = mgmt_status(status);
3157
3158 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3159 cmd_status_rsp, &mgmt_err);
3160 return;
3161 }
3162
3163 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3164 &match);
3165
3166 new_settings(hdev, match.sk);
3167
3168 if (match.sk)
3169 sock_put(match.sk);
3170}
3171
3172static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3173{
3174 struct mgmt_mode *cp = data;
3175 struct pending_cmd *cmd;
3176 struct hci_request req;
3177 u8 val, enabled;
3178 int err;
3179
3180 BT_DBG("request for %s", hdev->name);
3181
3182 if (!lmp_le_capable(hdev))
3183 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3184 MGMT_STATUS_NOT_SUPPORTED);
3185
3186 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3187 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3188 MGMT_STATUS_REJECTED);
3189
3190 if (cp->val != 0x00 && cp->val != 0x01)
3191 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3192 MGMT_STATUS_INVALID_PARAMS);
3193
3194 hci_dev_lock(hdev);
3195
3196 val = !!cp->val;
3197 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3198
3199 if (!hdev_is_powered(hdev) || val == enabled) {
3200 bool changed = false;
3201
3202 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3203 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3204 changed = true;
3205 }
3206
3207 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3208 if (err < 0)
3209 goto unlock;
3210
3211 if (changed)
3212 err = new_settings(hdev, sk);
3213
3214 goto unlock;
3215 }
3216
3217 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3218 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3219 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3220 MGMT_STATUS_BUSY);
3221 goto unlock;
3222 }
3223
3224 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3225 if (!cmd) {
3226 err = -ENOMEM;
3227 goto unlock;
3228 }
3229
3230 hci_req_init(&req, hdev);
3231
3232 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3233
3234 err = hci_req_run(&req, set_advertising_complete);
3235 if (err < 0)
3236 mgmt_pending_remove(cmd);
3237
3238unlock:
3239 hci_dev_unlock(hdev);
3240 return err;
3241}
3242
Johan Hedberg33e38b32013-03-15 17:07:05 -05003243static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3244{
3245 struct pending_cmd *cmd;
3246
3247 BT_DBG("status 0x%02x", status);
3248
3249 hci_dev_lock(hdev);
3250
3251 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3252 if (!cmd)
3253 goto unlock;
3254
3255 if (status) {
3256 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3257 mgmt_status(status));
3258 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003259 struct mgmt_mode *cp = cmd->param;
3260
3261 if (cp->val)
3262 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3263 else
3264 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3265
Johan Hedberg33e38b32013-03-15 17:07:05 -05003266 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3267 new_settings(hdev, cmd->sk);
3268 }
3269
3270 mgmt_pending_remove(cmd);
3271
3272unlock:
3273 hci_dev_unlock(hdev);
3274}
3275
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003276static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003277 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003278{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003279 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003280 struct pending_cmd *cmd;
3281 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003282 int err;
3283
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003284 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003285
Johan Hedberg56f87902013-10-02 13:43:13 +03003286 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3287 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003288 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3289 MGMT_STATUS_NOT_SUPPORTED);
3290
Johan Hedberga7e80f22013-01-09 16:05:19 +02003291 if (cp->val != 0x00 && cp->val != 0x01)
3292 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3293 MGMT_STATUS_INVALID_PARAMS);
3294
Johan Hedberg5400c042012-02-21 16:40:33 +02003295 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003296 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003297 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003298
3299 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003300 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003301 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003302
3303 hci_dev_lock(hdev);
3304
Johan Hedberg05cbf292013-03-15 17:07:07 -05003305 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3306 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3307 MGMT_STATUS_BUSY);
3308 goto unlock;
3309 }
3310
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003311 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3312 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3313 hdev);
3314 goto unlock;
3315 }
3316
Johan Hedberg33e38b32013-03-15 17:07:05 -05003317 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3318 data, len);
3319 if (!cmd) {
3320 err = -ENOMEM;
3321 goto unlock;
3322 }
3323
3324 hci_req_init(&req, hdev);
3325
Johan Hedberg406d7802013-03-15 17:07:09 -05003326 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003327
3328 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003329 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003330 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003331 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003332 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003333 }
3334
Johan Hedberg33e38b32013-03-15 17:07:05 -05003335unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003336 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003337
Antti Julkuf6422ec2011-06-22 13:11:56 +03003338 return err;
3339}
3340
Johan Hedberg0663ca22013-10-02 13:43:14 +03003341static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3342{
3343 struct pending_cmd *cmd;
3344
3345 BT_DBG("status 0x%02x", status);
3346
3347 hci_dev_lock(hdev);
3348
3349 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3350 if (!cmd)
3351 goto unlock;
3352
3353 if (status) {
3354 u8 mgmt_err = mgmt_status(status);
3355
3356 /* We need to restore the flag if related HCI commands
3357 * failed.
3358 */
3359 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3360
3361 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3362 } else {
3363 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3364 new_settings(hdev, cmd->sk);
3365 }
3366
3367 mgmt_pending_remove(cmd);
3368
3369unlock:
3370 hci_dev_unlock(hdev);
3371}
3372
3373static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3374{
3375 struct mgmt_mode *cp = data;
3376 struct pending_cmd *cmd;
3377 struct hci_request req;
3378 int err;
3379
3380 BT_DBG("request for %s", hdev->name);
3381
3382 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3383 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3384 MGMT_STATUS_NOT_SUPPORTED);
3385
3386 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3387 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3388 MGMT_STATUS_REJECTED);
3389
3390 if (cp->val != 0x00 && cp->val != 0x01)
3391 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3392 MGMT_STATUS_INVALID_PARAMS);
3393
3394 hci_dev_lock(hdev);
3395
3396 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3397 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3398 goto unlock;
3399 }
3400
3401 if (!hdev_is_powered(hdev)) {
3402 if (!cp->val) {
3403 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3404 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3405 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3406 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3407 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3408 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3409 }
3410
3411 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3412
3413 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3414 if (err < 0)
3415 goto unlock;
3416
3417 err = new_settings(hdev, sk);
3418 goto unlock;
3419 }
3420
3421 /* Reject disabling when powered on */
3422 if (!cp->val) {
3423 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3424 MGMT_STATUS_REJECTED);
3425 goto unlock;
3426 }
3427
3428 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3429 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3430 MGMT_STATUS_BUSY);
3431 goto unlock;
3432 }
3433
3434 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3435 if (!cmd) {
3436 err = -ENOMEM;
3437 goto unlock;
3438 }
3439
3440 /* We need to flip the bit already here so that hci_update_ad
3441 * generates the correct flags.
3442 */
3443 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3444
3445 hci_req_init(&req, hdev);
3446 hci_update_ad(&req);
3447 err = hci_req_run(&req, set_bredr_complete);
3448 if (err < 0)
3449 mgmt_pending_remove(cmd);
3450
3451unlock:
3452 hci_dev_unlock(hdev);
3453 return err;
3454}
3455
Johan Hedberg3f706b72013-01-20 14:27:16 +02003456static bool ltk_is_valid(struct mgmt_ltk_info *key)
3457{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003458 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3459 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003460 if (key->master != 0x00 && key->master != 0x01)
3461 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003462 if (!bdaddr_type_is_le(key->addr.type))
3463 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003464 return true;
3465}
3466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003467static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003468 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003469{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003470 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3471 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003472 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003473
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003474 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003475
3476 expected_len = sizeof(*cp) + key_count *
3477 sizeof(struct mgmt_ltk_info);
3478 if (expected_len != len) {
3479 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003480 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003481 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003482 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003483 }
3484
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003485 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003486
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003487 for (i = 0; i < key_count; i++) {
3488 struct mgmt_ltk_info *key = &cp->keys[i];
3489
Johan Hedberg3f706b72013-01-20 14:27:16 +02003490 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003491 return cmd_status(sk, hdev->id,
3492 MGMT_OP_LOAD_LONG_TERM_KEYS,
3493 MGMT_STATUS_INVALID_PARAMS);
3494 }
3495
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003496 hci_dev_lock(hdev);
3497
3498 hci_smp_ltks_clear(hdev);
3499
3500 for (i = 0; i < key_count; i++) {
3501 struct mgmt_ltk_info *key = &cp->keys[i];
3502 u8 type;
3503
3504 if (key->master)
3505 type = HCI_SMP_LTK;
3506 else
3507 type = HCI_SMP_LTK_SLAVE;
3508
Hemant Gupta4596fde2012-04-16 14:57:40 +05303509 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003510 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003511 type, 0, key->authenticated, key->val,
3512 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003513 }
3514
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003515 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3516 NULL, 0);
3517
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003518 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003519
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003520 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003521}
3522
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003523static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003524 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3525 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003526 bool var_len;
3527 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003528} mgmt_handlers[] = {
3529 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003530 { read_version, false, MGMT_READ_VERSION_SIZE },
3531 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3532 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3533 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3534 { set_powered, false, MGMT_SETTING_SIZE },
3535 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3536 { set_connectable, false, MGMT_SETTING_SIZE },
3537 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3538 { set_pairable, false, MGMT_SETTING_SIZE },
3539 { set_link_security, false, MGMT_SETTING_SIZE },
3540 { set_ssp, false, MGMT_SETTING_SIZE },
3541 { set_hs, false, MGMT_SETTING_SIZE },
3542 { set_le, false, MGMT_SETTING_SIZE },
3543 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3544 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3545 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3546 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3547 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3548 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3549 { disconnect, false, MGMT_DISCONNECT_SIZE },
3550 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3551 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3552 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3553 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3554 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3555 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3556 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3557 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3558 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3559 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3560 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3561 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3562 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3563 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3564 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3565 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3566 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3567 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3568 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003569 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003570 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003571 { set_bredr, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003572};
3573
3574
Johan Hedberg03811012010-12-08 00:21:06 +02003575int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3576{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003577 void *buf;
3578 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003579 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003580 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003581 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003582 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003583 int err;
3584
3585 BT_DBG("got %zu bytes", msglen);
3586
3587 if (msglen < sizeof(*hdr))
3588 return -EINVAL;
3589
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003590 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003591 if (!buf)
3592 return -ENOMEM;
3593
3594 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3595 err = -EFAULT;
3596 goto done;
3597 }
3598
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003599 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003600 opcode = __le16_to_cpu(hdr->opcode);
3601 index = __le16_to_cpu(hdr->index);
3602 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003603
3604 if (len != msglen - sizeof(*hdr)) {
3605 err = -EINVAL;
3606 goto done;
3607 }
3608
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003609 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003610 hdev = hci_dev_get(index);
3611 if (!hdev) {
3612 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003613 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003614 goto done;
3615 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003616
3617 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3618 err = cmd_status(sk, index, opcode,
3619 MGMT_STATUS_INVALID_INDEX);
3620 goto done;
3621 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003622 }
3623
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003624 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003625 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003626 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003627 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003628 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003629 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003630 }
3631
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003632 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003633 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003634 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003635 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003636 goto done;
3637 }
3638
Johan Hedbergbe22b542012-03-01 22:24:41 +02003639 handler = &mgmt_handlers[opcode];
3640
3641 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003642 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003643 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003644 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003645 goto done;
3646 }
3647
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003648 if (hdev)
3649 mgmt_init_hdev(sk, hdev);
3650
3651 cp = buf + sizeof(*hdr);
3652
Johan Hedbergbe22b542012-03-01 22:24:41 +02003653 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003654 if (err < 0)
3655 goto done;
3656
Johan Hedberg03811012010-12-08 00:21:06 +02003657 err = msglen;
3658
3659done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003660 if (hdev)
3661 hci_dev_put(hdev);
3662
Johan Hedberg03811012010-12-08 00:21:06 +02003663 kfree(buf);
3664 return err;
3665}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003666
Johan Hedberg744cf192011-11-08 20:40:14 +02003667int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003668{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003669 if (!mgmt_valid_hdev(hdev))
3670 return -ENOTSUPP;
3671
Johan Hedberg744cf192011-11-08 20:40:14 +02003672 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003673}
3674
Johan Hedberg744cf192011-11-08 20:40:14 +02003675int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003676{
Johan Hedberg5f159032012-03-02 03:13:19 +02003677 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003678
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003679 if (!mgmt_valid_hdev(hdev))
3680 return -ENOTSUPP;
3681
Johan Hedberg744cf192011-11-08 20:40:14 +02003682 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003683
Johan Hedberg744cf192011-11-08 20:40:14 +02003684 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003685}
3686
Johan Hedberg890ea892013-03-15 17:06:52 -05003687static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003688{
Johan Hedberg890ea892013-03-15 17:06:52 -05003689 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003690 u8 scan = 0;
3691
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003692 /* Ensure that fast connectable is disabled. This function will
3693 * not do anything if the page scan parameters are already what
3694 * they should be.
3695 */
3696 write_fast_connectable(req, false);
3697
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003698 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3699 scan |= SCAN_PAGE;
3700 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3701 scan |= SCAN_INQUIRY;
3702
Johan Hedberg890ea892013-03-15 17:06:52 -05003703 if (scan)
3704 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003705}
3706
Johan Hedberg229ab392013-03-15 17:06:53 -05003707static void powered_complete(struct hci_dev *hdev, u8 status)
3708{
3709 struct cmd_lookup match = { NULL, hdev };
3710
3711 BT_DBG("status 0x%02x", status);
3712
3713 hci_dev_lock(hdev);
3714
3715 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3716
3717 new_settings(hdev, match.sk);
3718
3719 hci_dev_unlock(hdev);
3720
3721 if (match.sk)
3722 sock_put(match.sk);
3723}
3724
Johan Hedberg70da6242013-03-15 17:06:51 -05003725static int powered_update_hci(struct hci_dev *hdev)
3726{
Johan Hedberg890ea892013-03-15 17:06:52 -05003727 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003728 u8 link_sec;
3729
Johan Hedberg890ea892013-03-15 17:06:52 -05003730 hci_req_init(&req, hdev);
3731
Johan Hedberg70da6242013-03-15 17:06:51 -05003732 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3733 !lmp_host_ssp_capable(hdev)) {
3734 u8 ssp = 1;
3735
Johan Hedberg890ea892013-03-15 17:06:52 -05003736 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003737 }
3738
Johan Hedbergc73eee92013-04-19 18:35:21 +03003739 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3740 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003741 struct hci_cp_write_le_host_supported cp;
3742
3743 cp.le = 1;
3744 cp.simul = lmp_le_br_capable(hdev);
3745
3746 /* Check first if we already have the right
3747 * host state (host features set)
3748 */
3749 if (cp.le != lmp_host_le_capable(hdev) ||
3750 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003751 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3752 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003753
3754 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3755 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003756 }
3757
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003758 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3759 u8 adv = 0x01;
3760
3761 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3762 }
3763
Johan Hedberg70da6242013-03-15 17:06:51 -05003764 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3765 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003766 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3767 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003768
3769 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003770 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3771 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003772 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003773 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003774 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003775 }
3776
Johan Hedberg229ab392013-03-15 17:06:53 -05003777 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003778}
3779
Johan Hedberg744cf192011-11-08 20:40:14 +02003780int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003781{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003782 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003783 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3784 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003785 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003786
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003787 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3788 return 0;
3789
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003790 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003791 if (powered_update_hci(hdev) == 0)
3792 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003793
Johan Hedberg229ab392013-03-15 17:06:53 -05003794 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3795 &match);
3796 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003797 }
3798
Johan Hedberg229ab392013-03-15 17:06:53 -05003799 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3800 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3801
3802 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3803 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3804 zero_cod, sizeof(zero_cod), NULL);
3805
3806new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003807 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003808
3809 if (match.sk)
3810 sock_put(match.sk);
3811
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003812 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003813}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003814
Johan Hedberg96570ff2013-05-29 09:51:29 +03003815int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3816{
3817 struct pending_cmd *cmd;
3818 u8 status;
3819
3820 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3821 if (!cmd)
3822 return -ENOENT;
3823
3824 if (err == -ERFKILL)
3825 status = MGMT_STATUS_RFKILLED;
3826 else
3827 status = MGMT_STATUS_FAILED;
3828
3829 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3830
3831 mgmt_pending_remove(cmd);
3832
3833 return err;
3834}
3835
Johan Hedberg744cf192011-11-08 20:40:14 +02003836int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003837{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003838 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003839 bool changed = false;
3840 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003841
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003842 if (discoverable) {
3843 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3844 changed = true;
3845 } else {
3846 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3847 changed = true;
3848 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003849
Johan Hedberged9b5f22012-02-21 20:47:06 +02003850 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003851 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003852
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003853 if (changed)
3854 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003855
Johan Hedberg73f22f62010-12-29 16:00:25 +02003856 if (match.sk)
3857 sock_put(match.sk);
3858
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003859 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003860}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003861
Johan Hedberg744cf192011-11-08 20:40:14 +02003862int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003863{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003864 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003865 bool changed = false;
3866 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003867
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003868 if (connectable) {
3869 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3870 changed = true;
3871 } else {
3872 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3873 changed = true;
3874 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003875
Johan Hedberg2b76f452013-03-15 17:07:04 -05003876 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003877
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003878 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003879 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003880
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003881 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003882}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003883
Johan Hedberg744cf192011-11-08 20:40:14 +02003884int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003885{
Johan Hedbergca69b792011-11-11 18:10:00 +02003886 u8 mgmt_err = mgmt_status(status);
3887
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003888 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003889 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003890 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003891
3892 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003893 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003894 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003895
3896 return 0;
3897}
3898
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003899int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3900 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003901{
Johan Hedberg86742e12011-11-07 23:13:38 +02003902 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003903
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003904 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003905
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003906 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003907 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003908 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003909 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003910 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003911 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003912
Johan Hedberg744cf192011-11-08 20:40:14 +02003913 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003914}
Johan Hedbergf7520542011-01-20 12:34:39 +02003915
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003916int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3917{
3918 struct mgmt_ev_new_long_term_key ev;
3919
3920 memset(&ev, 0, sizeof(ev));
3921
3922 ev.store_hint = persistent;
3923 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003924 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003925 ev.key.authenticated = key->authenticated;
3926 ev.key.enc_size = key->enc_size;
3927 ev.key.ediv = key->ediv;
3928
3929 if (key->type == HCI_SMP_LTK)
3930 ev.key.master = 1;
3931
3932 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3933 memcpy(ev.key.val, key->val, sizeof(key->val));
3934
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003935 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3936 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003937}
3938
Johan Hedbergafc747a2012-01-15 18:11:07 +02003939int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003940 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3941 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003942{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003943 char buf[512];
3944 struct mgmt_ev_device_connected *ev = (void *) buf;
3945 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003946
Johan Hedbergb644ba32012-01-17 21:48:47 +02003947 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003948 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003949
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003950 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003951
Johan Hedbergb644ba32012-01-17 21:48:47 +02003952 if (name_len > 0)
3953 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003954 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003955
3956 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003957 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003958 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003959
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003960 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003961
3962 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003963 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003964}
3965
Johan Hedberg8962ee72011-01-20 12:40:27 +02003966static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3967{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003968 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003969 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003970 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003971
Johan Hedberg88c3df12012-02-09 14:27:38 +02003972 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3973 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003974
Johan Hedbergaee9b212012-02-18 15:07:59 +02003975 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003976 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003977
3978 *sk = cmd->sk;
3979 sock_hold(*sk);
3980
Johan Hedberga664b5b2011-02-19 12:06:02 -03003981 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003982}
3983
Johan Hedberg124f6e32012-02-09 13:50:12 +02003984static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003985{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003986 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003987 struct mgmt_cp_unpair_device *cp = cmd->param;
3988 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003989
3990 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003991 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3992 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003993
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003994 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3995
Johan Hedbergaee9b212012-02-18 15:07:59 +02003996 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003997
3998 mgmt_pending_remove(cmd);
3999}
4000
Johan Hedbergafc747a2012-01-15 18:11:07 +02004001int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004002 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004003{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004004 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004005 struct sock *sk = NULL;
4006 int err;
4007
Johan Hedberg744cf192011-11-08 20:40:14 +02004008 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004009
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004010 bacpy(&ev.addr.bdaddr, bdaddr);
4011 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4012 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004013
Johan Hedbergafc747a2012-01-15 18:11:07 +02004014 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004015 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004016
4017 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004018 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004019
Johan Hedberg124f6e32012-02-09 13:50:12 +02004020 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004021 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004022
Johan Hedberg8962ee72011-01-20 12:40:27 +02004023 return err;
4024}
4025
Johan Hedberg88c3df12012-02-09 14:27:38 +02004026int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004027 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004028{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004029 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004030 struct pending_cmd *cmd;
4031 int err;
4032
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004033 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4034 hdev);
4035
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004036 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004037 if (!cmd)
4038 return -ENOENT;
4039
Johan Hedberg88c3df12012-02-09 14:27:38 +02004040 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004041 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004042
Johan Hedberg88c3df12012-02-09 14:27:38 +02004043 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004044 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004045
Johan Hedberga664b5b2011-02-19 12:06:02 -03004046 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004047
4048 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004049}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004050
Johan Hedberg48264f02011-11-09 13:58:58 +02004051int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004052 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004053{
4054 struct mgmt_ev_connect_failed ev;
4055
Johan Hedberg4c659c32011-11-07 23:13:39 +02004056 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004057 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004058 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004059
Johan Hedberg744cf192011-11-08 20:40:14 +02004060 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004061}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004062
Johan Hedberg744cf192011-11-08 20:40:14 +02004063int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004064{
4065 struct mgmt_ev_pin_code_request ev;
4066
Johan Hedbergd8457692012-02-17 14:24:57 +02004067 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004068 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004069 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004070
Johan Hedberg744cf192011-11-08 20:40:14 +02004071 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004072 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004073}
4074
Johan Hedberg744cf192011-11-08 20:40:14 +02004075int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004076 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004077{
4078 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004079 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004080 int err;
4081
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004082 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004083 if (!cmd)
4084 return -ENOENT;
4085
Johan Hedbergd8457692012-02-17 14:24:57 +02004086 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004087 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004088
Johan Hedbergaee9b212012-02-18 15:07:59 +02004089 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004090 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004091
Johan Hedberga664b5b2011-02-19 12:06:02 -03004092 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004093
4094 return err;
4095}
4096
Johan Hedberg744cf192011-11-08 20:40:14 +02004097int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004098 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004099{
4100 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004101 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004102 int err;
4103
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004104 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004105 if (!cmd)
4106 return -ENOENT;
4107
Johan Hedbergd8457692012-02-17 14:24:57 +02004108 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004109 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004110
Johan Hedbergaee9b212012-02-18 15:07:59 +02004111 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004112 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004113
Johan Hedberga664b5b2011-02-19 12:06:02 -03004114 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004115
4116 return err;
4117}
Johan Hedberga5c29682011-02-19 12:05:57 -03004118
Johan Hedberg744cf192011-11-08 20:40:14 +02004119int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004120 u8 link_type, u8 addr_type, __le32 value,
4121 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004122{
4123 struct mgmt_ev_user_confirm_request ev;
4124
Johan Hedberg744cf192011-11-08 20:40:14 +02004125 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004126
Johan Hedberg272d90d2012-02-09 15:26:12 +02004127 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004128 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004129 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004130 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004131
Johan Hedberg744cf192011-11-08 20:40:14 +02004132 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004133 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004134}
4135
Johan Hedberg272d90d2012-02-09 15:26:12 +02004136int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004137 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004138{
4139 struct mgmt_ev_user_passkey_request ev;
4140
4141 BT_DBG("%s", hdev->name);
4142
Johan Hedberg272d90d2012-02-09 15:26:12 +02004143 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004144 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004145
4146 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004147 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004148}
4149
Brian Gix0df4c182011-11-16 13:53:13 -08004150static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004151 u8 link_type, u8 addr_type, u8 status,
4152 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004153{
4154 struct pending_cmd *cmd;
4155 struct mgmt_rp_user_confirm_reply rp;
4156 int err;
4157
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004158 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004159 if (!cmd)
4160 return -ENOENT;
4161
Johan Hedberg272d90d2012-02-09 15:26:12 +02004162 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004163 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004164 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004165 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004166
Johan Hedberga664b5b2011-02-19 12:06:02 -03004167 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004168
4169 return err;
4170}
4171
Johan Hedberg744cf192011-11-08 20:40:14 +02004172int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004173 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004174{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004175 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004176 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004177}
4178
Johan Hedberg272d90d2012-02-09 15:26:12 +02004179int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004180 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004181{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004182 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004183 status,
4184 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004185}
Johan Hedberg2a611692011-02-19 12:06:00 -03004186
Brian Gix604086b2011-11-23 08:28:33 -08004187int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004188 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004189{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004190 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004191 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004192}
4193
Johan Hedberg272d90d2012-02-09 15:26:12 +02004194int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004195 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004196{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004197 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004198 status,
4199 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004200}
4201
Johan Hedberg92a25252012-09-06 18:39:26 +03004202int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4203 u8 link_type, u8 addr_type, u32 passkey,
4204 u8 entered)
4205{
4206 struct mgmt_ev_passkey_notify ev;
4207
4208 BT_DBG("%s", hdev->name);
4209
4210 bacpy(&ev.addr.bdaddr, bdaddr);
4211 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4212 ev.passkey = __cpu_to_le32(passkey);
4213 ev.entered = entered;
4214
4215 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4216}
4217
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004218int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004219 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004220{
4221 struct mgmt_ev_auth_failed ev;
4222
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004223 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004224 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004225 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004226
Johan Hedberg744cf192011-11-08 20:40:14 +02004227 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004228}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004229
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004230int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4231{
4232 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004233 bool changed = false;
4234 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004235
4236 if (status) {
4237 u8 mgmt_err = mgmt_status(status);
4238 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004239 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004240 return 0;
4241 }
4242
Johan Hedberg47990ea2012-02-22 11:58:37 +02004243 if (test_bit(HCI_AUTH, &hdev->flags)) {
4244 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4245 changed = true;
4246 } else {
4247 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4248 changed = true;
4249 }
4250
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004251 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004252 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004253
Johan Hedberg47990ea2012-02-22 11:58:37 +02004254 if (changed)
4255 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004256
4257 if (match.sk)
4258 sock_put(match.sk);
4259
4260 return err;
4261}
4262
Johan Hedberg890ea892013-03-15 17:06:52 -05004263static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004264{
Johan Hedberg890ea892013-03-15 17:06:52 -05004265 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004266 struct hci_cp_write_eir cp;
4267
Johan Hedberg976eb202012-10-24 21:12:01 +03004268 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004269 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004270
Johan Hedbergc80da272012-02-22 15:38:48 +02004271 memset(hdev->eir, 0, sizeof(hdev->eir));
4272
Johan Hedbergcacaf522012-02-21 00:52:42 +02004273 memset(&cp, 0, sizeof(cp));
4274
Johan Hedberg890ea892013-03-15 17:06:52 -05004275 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004276}
4277
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004278int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004279{
4280 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004281 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004282 bool changed = false;
4283 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004284
4285 if (status) {
4286 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004287
4288 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004289 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004290 err = new_settings(hdev, NULL);
4291
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004292 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4293 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004294
4295 return err;
4296 }
4297
4298 if (enable) {
4299 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4300 changed = true;
4301 } else {
4302 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4303 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004304 }
4305
4306 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4307
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004308 if (changed)
4309 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004310
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004311 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004312 sock_put(match.sk);
4313
Johan Hedberg890ea892013-03-15 17:06:52 -05004314 hci_req_init(&req, hdev);
4315
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004316 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004317 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004318 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004319 clear_eir(&req);
4320
4321 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004322
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004323 return err;
4324}
4325
Johan Hedberg92da6092013-03-15 17:06:55 -05004326static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004327{
4328 struct cmd_lookup *match = data;
4329
Johan Hedberg90e70452012-02-23 23:09:40 +02004330 if (match->sk == NULL) {
4331 match->sk = cmd->sk;
4332 sock_hold(match->sk);
4333 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004334}
4335
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004336int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004337 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004338{
Johan Hedberg90e70452012-02-23 23:09:40 +02004339 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4340 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004341
Johan Hedberg92da6092013-03-15 17:06:55 -05004342 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4343 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4344 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004345
4346 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004347 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4348 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004349
4350 if (match.sk)
4351 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004352
4353 return err;
4354}
4355
Johan Hedberg744cf192011-11-08 20:40:14 +02004356int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004357{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004358 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004359 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004360
Johan Hedberg13928972013-03-15 17:07:00 -05004361 if (status)
4362 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004363
4364 memset(&ev, 0, sizeof(ev));
4365 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004366 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004367
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004368 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004369 if (!cmd) {
4370 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004371
Johan Hedberg13928972013-03-15 17:07:00 -05004372 /* If this is a HCI command related to powering on the
4373 * HCI dev don't send any mgmt signals.
4374 */
4375 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4376 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004377 }
4378
Johan Hedberg13928972013-03-15 17:07:00 -05004379 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4380 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004381}
Szymon Jancc35938b2011-03-22 13:12:21 +01004382
Johan Hedberg744cf192011-11-08 20:40:14 +02004383int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004384 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004385{
4386 struct pending_cmd *cmd;
4387 int err;
4388
Johan Hedberg744cf192011-11-08 20:40:14 +02004389 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004390
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004391 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004392 if (!cmd)
4393 return -ENOENT;
4394
4395 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004396 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4397 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004398 } else {
4399 struct mgmt_rp_read_local_oob_data rp;
4400
4401 memcpy(rp.hash, hash, sizeof(rp.hash));
4402 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4403
Johan Hedberg744cf192011-11-08 20:40:14 +02004404 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004405 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4406 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004407 }
4408
4409 mgmt_pending_remove(cmd);
4410
4411 return err;
4412}
Johan Hedberge17acd42011-03-30 23:57:16 +03004413
Johan Hedberg48264f02011-11-09 13:58:58 +02004414int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004415 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4416 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004417{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004418 char buf[512];
4419 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004420 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004421
Andre Guedes12602d02013-04-30 15:29:40 -03004422 if (!hci_discovery_active(hdev))
4423 return -EPERM;
4424
Johan Hedberg1dc06092012-01-15 21:01:23 +02004425 /* Leave 5 bytes for a potential CoD field */
4426 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004427 return -EINVAL;
4428
Johan Hedberg1dc06092012-01-15 21:01:23 +02004429 memset(buf, 0, sizeof(buf));
4430
Johan Hedberge319d2e2012-01-15 19:51:59 +02004431 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004432 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004433 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004434 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304435 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004436 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304437 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004438
Johan Hedberg1dc06092012-01-15 21:01:23 +02004439 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004440 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004441
Johan Hedberg1dc06092012-01-15 21:01:23 +02004442 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4443 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004444 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004445
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004446 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004447 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004448
Johan Hedberge319d2e2012-01-15 19:51:59 +02004449 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004450}
Johan Hedberga88a9652011-03-30 13:18:12 +03004451
Johan Hedbergb644ba32012-01-17 21:48:47 +02004452int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004453 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004454{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004455 struct mgmt_ev_device_found *ev;
4456 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4457 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004458
Johan Hedbergb644ba32012-01-17 21:48:47 +02004459 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004460
Johan Hedbergb644ba32012-01-17 21:48:47 +02004461 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004462
Johan Hedbergb644ba32012-01-17 21:48:47 +02004463 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004464 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004465 ev->rssi = rssi;
4466
4467 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004468 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004469
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004470 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004471
Johan Hedberg053c7e02012-02-04 00:06:00 +02004472 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004473 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004474}
Johan Hedberg314b2382011-04-27 10:29:57 -04004475
Johan Hedberg744cf192011-11-08 20:40:14 +02004476int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004477{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004478 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004479 struct pending_cmd *cmd;
4480
Andre Guedes343fb142011-11-22 17:14:19 -03004481 BT_DBG("%s discovering %u", hdev->name, discovering);
4482
Johan Hedberg164a6e72011-11-01 17:06:44 +02004483 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004484 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004485 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004486 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004487
4488 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004489 u8 type = hdev->discovery.type;
4490
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004491 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4492 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004493 mgmt_pending_remove(cmd);
4494 }
4495
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004496 memset(&ev, 0, sizeof(ev));
4497 ev.type = hdev->discovery.type;
4498 ev.discovering = discovering;
4499
4500 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004501}
Antti Julku5e762442011-08-25 16:48:02 +03004502
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004503int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004504{
4505 struct pending_cmd *cmd;
4506 struct mgmt_ev_device_blocked ev;
4507
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004508 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004509
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004510 bacpy(&ev.addr.bdaddr, bdaddr);
4511 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004512
Johan Hedberg744cf192011-11-08 20:40:14 +02004513 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004514 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004515}
4516
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004517int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004518{
4519 struct pending_cmd *cmd;
4520 struct mgmt_ev_device_unblocked ev;
4521
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004522 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004523
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004524 bacpy(&ev.addr.bdaddr, bdaddr);
4525 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004526
Johan Hedberg744cf192011-11-08 20:40:14 +02004527 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004528 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004529}