blob: 2fb4d35e04dc0c1d30e41649f81d0b4e970bbc42 [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
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070036#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020037
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070076 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030077 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030078 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070079 MGMT_OP_SET_STATIC_ADDRESS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020080};
81
82static const u16 mgmt_events[] = {
83 MGMT_EV_CONTROLLER_ERROR,
84 MGMT_EV_INDEX_ADDED,
85 MGMT_EV_INDEX_REMOVED,
86 MGMT_EV_NEW_SETTINGS,
87 MGMT_EV_CLASS_OF_DEV_CHANGED,
88 MGMT_EV_LOCAL_NAME_CHANGED,
89 MGMT_EV_NEW_LINK_KEY,
90 MGMT_EV_NEW_LONG_TERM_KEY,
91 MGMT_EV_DEVICE_CONNECTED,
92 MGMT_EV_DEVICE_DISCONNECTED,
93 MGMT_EV_CONNECT_FAILED,
94 MGMT_EV_PIN_CODE_REQUEST,
95 MGMT_EV_USER_CONFIRM_REQUEST,
96 MGMT_EV_USER_PASSKEY_REQUEST,
97 MGMT_EV_AUTH_FAILED,
98 MGMT_EV_DEVICE_FOUND,
99 MGMT_EV_DISCOVERING,
100 MGMT_EV_DEVICE_BLOCKED,
101 MGMT_EV_DEVICE_UNBLOCKED,
102 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300103 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200104};
105
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800106#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200107
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200108#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
109 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
110
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200111struct pending_cmd {
112 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200113 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100115 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300117 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118};
119
Johan Hedbergca69b792011-11-11 18:10:00 +0200120/* HCI to MGMT error code conversion table */
121static u8 mgmt_status_table[] = {
122 MGMT_STATUS_SUCCESS,
123 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
124 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
125 MGMT_STATUS_FAILED, /* Hardware Failure */
126 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
127 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
128 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
129 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
130 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
132 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
133 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
134 MGMT_STATUS_BUSY, /* Command Disallowed */
135 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
136 MGMT_STATUS_REJECTED, /* Rejected Security */
137 MGMT_STATUS_REJECTED, /* Rejected Personal */
138 MGMT_STATUS_TIMEOUT, /* Host Timeout */
139 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
140 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
141 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
142 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
143 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
144 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
145 MGMT_STATUS_BUSY, /* Repeated Attempts */
146 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
147 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
148 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
149 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
150 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
151 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
153 MGMT_STATUS_FAILED, /* Unspecified Error */
154 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
155 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
156 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
157 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
158 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
159 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
160 MGMT_STATUS_FAILED, /* Unit Link Key Used */
161 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
162 MGMT_STATUS_TIMEOUT, /* Instant Passed */
163 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
164 MGMT_STATUS_FAILED, /* Transaction Collision */
165 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
166 MGMT_STATUS_REJECTED, /* QoS Rejected */
167 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
168 MGMT_STATUS_REJECTED, /* Insufficient Security */
169 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
170 MGMT_STATUS_BUSY, /* Role Switch Pending */
171 MGMT_STATUS_FAILED, /* Slot Violation */
172 MGMT_STATUS_FAILED, /* Role Switch Failed */
173 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
174 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
175 MGMT_STATUS_BUSY, /* Host Busy Pairing */
176 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
177 MGMT_STATUS_BUSY, /* Controller Busy */
178 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
179 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
180 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
181 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
182 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
183};
184
185static u8 mgmt_status(u8 hci_status)
186{
187 if (hci_status < ARRAY_SIZE(mgmt_status_table))
188 return mgmt_status_table[hci_status];
189
190 return MGMT_STATUS_FAILED;
191}
192
Szymon Janc4e51eae2011-02-25 19:05:48 +0100193static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200194{
195 struct sk_buff *skb;
196 struct mgmt_hdr *hdr;
197 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300198 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200199
Szymon Janc34eb5252011-02-28 14:10:08 +0100200 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Andre Guedes790eff42012-06-07 19:05:46 -0300202 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203 if (!skb)
204 return -ENOMEM;
205
206 hdr = (void *) skb_put(skb, sizeof(*hdr));
207
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530208 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100209 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200210 hdr->len = cpu_to_le16(sizeof(*ev));
211
212 ev = (void *) skb_put(skb, sizeof(*ev));
213 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200214 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200215
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300216 err = sock_queue_rcv_skb(sk, skb);
217 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200218 kfree_skb(skb);
219
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300220 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221}
222
Johan Hedbergaee9b212012-02-18 15:07:59 +0200223static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300224 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200225{
226 struct sk_buff *skb;
227 struct mgmt_hdr *hdr;
228 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200230
231 BT_DBG("sock %p", sk);
232
Andre Guedes790eff42012-06-07 19:05:46 -0300233 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200234 if (!skb)
235 return -ENOMEM;
236
237 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200238
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530239 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100240 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200241 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200242
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200244 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200245 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100246
247 if (rp)
248 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200249
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300250 err = sock_queue_rcv_skb(sk, skb);
251 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 kfree_skb(skb);
253
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100254 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200255}
256
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300257static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
258 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200259{
260 struct mgmt_rp_read_version rp;
261
262 BT_DBG("sock %p", sk);
263
264 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200265 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200266
Johan Hedbergaee9b212012-02-18 15:07:59 +0200267 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300268 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200269}
270
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
272 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200273{
274 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200275 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
276 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200277 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200278 size_t rp_size;
279 int i, err;
280
281 BT_DBG("sock %p", sk);
282
283 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
284
285 rp = kmalloc(rp_size, GFP_KERNEL);
286 if (!rp)
287 return -ENOMEM;
288
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200289 rp->num_commands = __constant_cpu_to_le16(num_commands);
290 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200291
292 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
293 put_unaligned_le16(mgmt_commands[i], opcode);
294
295 for (i = 0; i < num_events; i++, opcode++)
296 put_unaligned_le16(mgmt_events[i], opcode);
297
Johan Hedbergaee9b212012-02-18 15:07:59 +0200298 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300299 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200300 kfree(rp);
301
302 return err;
303}
304
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300305static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
306 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200307{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200308 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200309 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200310 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300312 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313
314 BT_DBG("sock %p", sk);
315
316 read_lock(&hci_dev_list_lock);
317
318 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300319 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700320 if (d->dev_type == HCI_BREDR)
321 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 }
323
Johan Hedberga38528f2011-01-22 06:46:43 +0200324 rp_len = sizeof(*rp) + (2 * count);
325 rp = kmalloc(rp_len, GFP_ATOMIC);
326 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100327 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330
Johan Hedberg476e44c2012-10-19 20:10:46 +0300331 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200332 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200333 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200334 continue;
335
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700336 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
337 continue;
338
Marcel Holtmann1514b892013-10-06 08:25:01 -0700339 if (d->dev_type == HCI_BREDR) {
340 rp->index[count++] = cpu_to_le16(d->id);
341 BT_DBG("Added hci%u", d->id);
342 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343 }
344
Johan Hedberg476e44c2012-10-19 20:10:46 +0300345 rp->num_controllers = cpu_to_le16(count);
346 rp_len = sizeof(*rp) + (2 * count);
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 read_unlock(&hci_dev_list_lock);
349
Johan Hedbergaee9b212012-02-18 15:07:59 +0200350 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300351 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352
Johan Hedberga38528f2011-01-22 06:46:43 +0200353 kfree(rp);
354
355 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356}
357
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200358static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200359{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200364
Andre Guedes9a1a1992012-07-24 15:03:48 -0300365 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200367
Andre Guedesed3fa312012-07-24 15:03:46 -0300368 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300369 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500370 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
371 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300372 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 settings |= MGMT_SETTING_BREDR;
374 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100375 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700376 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100377
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300378 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200379 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300380 settings |= MGMT_SETTING_ADVERTISING;
381 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200382
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200383 return settings;
384}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200385
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200386static u32 get_current_settings(struct hci_dev *hdev)
387{
388 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200389
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200390 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100391 settings |= MGMT_SETTING_POWERED;
392
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200393 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394 settings |= MGMT_SETTING_CONNECTABLE;
395
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500396 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
397 settings |= MGMT_SETTING_FAST_CONNECTABLE;
398
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200399 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 settings |= MGMT_SETTING_DISCOVERABLE;
401
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200402 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_PAIRABLE;
404
Johan Hedberg56f87902013-10-02 13:43:13 +0300405 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_BREDR;
407
Johan Hedberg06199cf2012-02-22 16:37:11 +0200408 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200410
Johan Hedberg47990ea2012-02-22 11:58:37 +0200411 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200414 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200417 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
418 settings |= MGMT_SETTING_HS;
419
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200420 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300421 settings |= MGMT_SETTING_ADVERTISING;
422
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200424}
425
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300426#define PNP_INFO_SVCLASS_ID 0x1200
427
Johan Hedberg213202e2013-01-27 00:31:33 +0200428static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
429{
430 u8 *ptr = data, *uuids_start = NULL;
431 struct bt_uuid *uuid;
432
433 if (len < 4)
434 return ptr;
435
436 list_for_each_entry(uuid, &hdev->uuids, list) {
437 u16 uuid16;
438
439 if (uuid->size != 16)
440 continue;
441
442 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
443 if (uuid16 < 0x1100)
444 continue;
445
446 if (uuid16 == PNP_INFO_SVCLASS_ID)
447 continue;
448
449 if (!uuids_start) {
450 uuids_start = ptr;
451 uuids_start[0] = 1;
452 uuids_start[1] = EIR_UUID16_ALL;
453 ptr += 2;
454 }
455
456 /* Stop if not enough space to put next UUID */
457 if ((ptr - data) + sizeof(u16) > len) {
458 uuids_start[1] = EIR_UUID16_SOME;
459 break;
460 }
461
462 *ptr++ = (uuid16 & 0x00ff);
463 *ptr++ = (uuid16 & 0xff00) >> 8;
464 uuids_start[0] += sizeof(uuid16);
465 }
466
467 return ptr;
468}
469
Johan Hedbergcdf19632013-01-27 00:31:34 +0200470static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
471{
472 u8 *ptr = data, *uuids_start = NULL;
473 struct bt_uuid *uuid;
474
475 if (len < 6)
476 return ptr;
477
478 list_for_each_entry(uuid, &hdev->uuids, list) {
479 if (uuid->size != 32)
480 continue;
481
482 if (!uuids_start) {
483 uuids_start = ptr;
484 uuids_start[0] = 1;
485 uuids_start[1] = EIR_UUID32_ALL;
486 ptr += 2;
487 }
488
489 /* Stop if not enough space to put next UUID */
490 if ((ptr - data) + sizeof(u32) > len) {
491 uuids_start[1] = EIR_UUID32_SOME;
492 break;
493 }
494
495 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
496 ptr += sizeof(u32);
497 uuids_start[0] += sizeof(u32);
498 }
499
500 return ptr;
501}
502
Johan Hedbergc00d5752013-01-27 00:31:35 +0200503static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
504{
505 u8 *ptr = data, *uuids_start = NULL;
506 struct bt_uuid *uuid;
507
508 if (len < 18)
509 return ptr;
510
511 list_for_each_entry(uuid, &hdev->uuids, list) {
512 if (uuid->size != 128)
513 continue;
514
515 if (!uuids_start) {
516 uuids_start = ptr;
517 uuids_start[0] = 1;
518 uuids_start[1] = EIR_UUID128_ALL;
519 ptr += 2;
520 }
521
522 /* Stop if not enough space to put next UUID */
523 if ((ptr - data) + 16 > len) {
524 uuids_start[1] = EIR_UUID128_SOME;
525 break;
526 }
527
528 memcpy(ptr, uuid->uuid, 16);
529 ptr += 16;
530 uuids_start[0] += 16;
531 }
532
533 return ptr;
534}
535
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300536static void create_eir(struct hci_dev *hdev, u8 *data)
537{
538 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 size_t name_len;
540
541 name_len = strlen(hdev->dev_name);
542
543 if (name_len > 0) {
544 /* EIR Data type */
545 if (name_len > 48) {
546 name_len = 48;
547 ptr[1] = EIR_NAME_SHORT;
548 } else
549 ptr[1] = EIR_NAME_COMPLETE;
550
551 /* EIR Data length */
552 ptr[0] = name_len + 1;
553
554 memcpy(ptr + 2, hdev->dev_name, name_len);
555
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300556 ptr += (name_len + 2);
557 }
558
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100559 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700560 ptr[0] = 2;
561 ptr[1] = EIR_TX_POWER;
562 ptr[2] = (u8) hdev->inq_tx_power;
563
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700564 ptr += 3;
565 }
566
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700567 if (hdev->devid_source > 0) {
568 ptr[0] = 9;
569 ptr[1] = EIR_DEVICE_ID;
570
571 put_unaligned_le16(hdev->devid_source, ptr + 2);
572 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
573 put_unaligned_le16(hdev->devid_product, ptr + 6);
574 put_unaligned_le16(hdev->devid_version, ptr + 8);
575
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700576 ptr += 10;
577 }
578
Johan Hedberg213202e2013-01-27 00:31:33 +0200579 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200580 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200581 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300582}
583
Johan Hedberg890ea892013-03-15 17:06:52 -0500584static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300585{
Johan Hedberg890ea892013-03-15 17:06:52 -0500586 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300587 struct hci_cp_write_eir cp;
588
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200589 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500590 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200591
Johan Hedberg976eb202012-10-24 21:12:01 +0300592 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500593 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300594
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200595 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500596 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300597
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200598 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500599 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300600
601 memset(&cp, 0, sizeof(cp));
602
603 create_eir(hdev, cp.data);
604
605 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500606 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300607
608 memcpy(hdev->eir, cp.data, sizeof(cp.data));
609
Johan Hedberg890ea892013-03-15 17:06:52 -0500610 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300611}
612
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200613static u8 get_service_classes(struct hci_dev *hdev)
614{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300615 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200616 u8 val = 0;
617
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300618 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200619 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620
621 return val;
622}
623
Johan Hedberg890ea892013-03-15 17:06:52 -0500624static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200625{
Johan Hedberg890ea892013-03-15 17:06:52 -0500626 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627 u8 cod[3];
628
629 BT_DBG("%s", hdev->name);
630
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200631 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500632 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200633
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200634 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500635 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200636
637 cod[0] = hdev->minor_class;
638 cod[1] = hdev->major_class;
639 cod[2] = get_service_classes(hdev);
640
641 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500642 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200643
Johan Hedberg890ea892013-03-15 17:06:52 -0500644 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200645}
646
Johan Hedberg7d785252011-12-15 00:47:39 +0200647static void service_cache_off(struct work_struct *work)
648{
649 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300650 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500651 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200652
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200653 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200654 return;
655
Johan Hedberg890ea892013-03-15 17:06:52 -0500656 hci_req_init(&req, hdev);
657
Johan Hedberg7d785252011-12-15 00:47:39 +0200658 hci_dev_lock(hdev);
659
Johan Hedberg890ea892013-03-15 17:06:52 -0500660 update_eir(&req);
661 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200662
663 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500664
665 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200666}
667
Johan Hedberg6a919082012-02-28 06:17:26 +0200668static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200669{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200670 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200671 return;
672
Johan Hedberg4f87da82012-03-02 19:55:56 +0200673 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200674
Johan Hedberg4f87da82012-03-02 19:55:56 +0200675 /* Non-mgmt controlled devices get this bit set
676 * implicitly so that pairing works for them, however
677 * for mgmt we require user-space to explicitly enable
678 * it
679 */
680 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200681}
682
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200683static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300684 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200685{
686 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200687
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200688 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300690 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200691
Johan Hedberg03811012010-12-08 00:21:06 +0200692 memset(&rp, 0, sizeof(rp));
693
Johan Hedberg03811012010-12-08 00:21:06 +0200694 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200695
696 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200697 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200698
699 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
700 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
701
702 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200703
704 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200705 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200706
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300707 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200708
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200709 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300710 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200711}
712
713static void mgmt_pending_free(struct pending_cmd *cmd)
714{
715 sock_put(cmd->sk);
716 kfree(cmd->param);
717 kfree(cmd);
718}
719
720static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300721 struct hci_dev *hdev, void *data,
722 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200723{
724 struct pending_cmd *cmd;
725
Andre Guedes12b94562012-06-07 19:05:45 -0300726 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200727 if (!cmd)
728 return NULL;
729
730 cmd->opcode = opcode;
731 cmd->index = hdev->id;
732
Andre Guedes12b94562012-06-07 19:05:45 -0300733 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200734 if (!cmd->param) {
735 kfree(cmd);
736 return NULL;
737 }
738
739 if (data)
740 memcpy(cmd->param, data, len);
741
742 cmd->sk = sk;
743 sock_hold(sk);
744
745 list_add(&cmd->list, &hdev->mgmt_pending);
746
747 return cmd;
748}
749
750static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300751 void (*cb)(struct pending_cmd *cmd,
752 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300753 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200754{
Andre Guedesa3d09352013-02-01 11:21:30 -0300755 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Andre Guedesa3d09352013-02-01 11:21:30 -0300757 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200758 if (opcode > 0 && cmd->opcode != opcode)
759 continue;
760
761 cb(cmd, data);
762 }
763}
764
765static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
766{
767 struct pending_cmd *cmd;
768
769 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
770 if (cmd->opcode == opcode)
771 return cmd;
772 }
773
774 return NULL;
775}
776
777static void mgmt_pending_remove(struct pending_cmd *cmd)
778{
779 list_del(&cmd->list);
780 mgmt_pending_free(cmd);
781}
782
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200783static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200784{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200785 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200786
Johan Hedbergaee9b212012-02-18 15:07:59 +0200787 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300788 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200789}
790
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200791static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300792 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200793{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300794 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200795 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200796 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200797
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200798 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200799
Johan Hedberga7e80f22013-01-09 16:05:19 +0200800 if (cp->val != 0x00 && cp->val != 0x01)
801 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
802 MGMT_STATUS_INVALID_PARAMS);
803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300804 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300806 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
807 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
808 MGMT_STATUS_BUSY);
809 goto failed;
810 }
811
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100812 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
813 cancel_delayed_work(&hdev->power_off);
814
815 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200816 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
817 data, len);
818 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100819 goto failed;
820 }
821 }
822
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200823 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200824 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200825 goto failed;
826 }
827
Johan Hedberg03811012010-12-08 00:21:06 +0200828 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
829 if (!cmd) {
830 err = -ENOMEM;
831 goto failed;
832 }
833
834 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200835 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200836 else
Johan Hedberg19202572013-01-14 22:33:51 +0200837 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200838
839 err = 0;
840
841failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300842 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200843 return err;
844}
845
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300846static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
847 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200848{
849 struct sk_buff *skb;
850 struct mgmt_hdr *hdr;
851
Andre Guedes790eff42012-06-07 19:05:46 -0300852 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200853 if (!skb)
854 return -ENOMEM;
855
856 hdr = (void *) skb_put(skb, sizeof(*hdr));
857 hdr->opcode = cpu_to_le16(event);
858 if (hdev)
859 hdr->index = cpu_to_le16(hdev->id);
860 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530861 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200862 hdr->len = cpu_to_le16(data_len);
863
864 if (data)
865 memcpy(skb_put(skb, data_len), data, data_len);
866
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100867 /* Time stamp */
868 __net_timestamp(skb);
869
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200870 hci_send_to_control(skb, skip_sk);
871 kfree_skb(skb);
872
873 return 0;
874}
875
876static int new_settings(struct hci_dev *hdev, struct sock *skip)
877{
878 __le32 ev;
879
880 ev = cpu_to_le32(get_current_settings(hdev));
881
882 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
883}
884
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300885struct cmd_lookup {
886 struct sock *sk;
887 struct hci_dev *hdev;
888 u8 mgmt_status;
889};
890
891static void settings_rsp(struct pending_cmd *cmd, void *data)
892{
893 struct cmd_lookup *match = data;
894
895 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
896
897 list_del(&cmd->list);
898
899 if (match->sk == NULL) {
900 match->sk = cmd->sk;
901 sock_hold(match->sk);
902 }
903
904 mgmt_pending_free(cmd);
905}
906
907static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
908{
909 u8 *status = data;
910
911 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
912 mgmt_pending_remove(cmd);
913}
914
Johan Hedberge6fe7982013-10-02 15:45:22 +0300915static u8 mgmt_bredr_support(struct hci_dev *hdev)
916{
917 if (!lmp_bredr_capable(hdev))
918 return MGMT_STATUS_NOT_SUPPORTED;
919 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
920 return MGMT_STATUS_REJECTED;
921 else
922 return MGMT_STATUS_SUCCESS;
923}
924
925static u8 mgmt_le_support(struct hci_dev *hdev)
926{
927 if (!lmp_le_capable(hdev))
928 return MGMT_STATUS_NOT_SUPPORTED;
929 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
930 return MGMT_STATUS_REJECTED;
931 else
932 return MGMT_STATUS_SUCCESS;
933}
934
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200935static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300936 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200937{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300938 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200939 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200940 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300941 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200942 int err;
943
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200944 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200945
Johan Hedberge6fe7982013-10-02 15:45:22 +0300946 status = mgmt_bredr_support(hdev);
947 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300948 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300949 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300950
Johan Hedberga7e80f22013-01-09 16:05:19 +0200951 if (cp->val != 0x00 && cp->val != 0x01)
952 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
953 MGMT_STATUS_INVALID_PARAMS);
954
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700955 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100956 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200957 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300958 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300960 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200961
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200963 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300964 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200965 goto failed;
966 }
967
968 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300969 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200970 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300971 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200972 goto failed;
973 }
974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200976 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300977 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200978 goto failed;
979 }
980
981 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200982 bool changed = false;
983
984 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
985 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
986 changed = true;
987 }
988
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200989 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200990 if (err < 0)
991 goto failed;
992
993 if (changed)
994 err = new_settings(hdev, sk);
995
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200996 goto failed;
997 }
998
999 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001000 if (hdev->discov_timeout > 0) {
1001 cancel_delayed_work(&hdev->discov_off);
1002 hdev->discov_timeout = 0;
1003 }
1004
1005 if (cp->val && timeout > 0) {
1006 hdev->discov_timeout = timeout;
1007 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1008 msecs_to_jiffies(hdev->discov_timeout * 1000));
1009 }
1010
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001011 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001012 goto failed;
1013 }
1014
1015 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1016 if (!cmd) {
1017 err = -ENOMEM;
1018 goto failed;
1019 }
1020
1021 scan = SCAN_PAGE;
1022
1023 if (cp->val)
1024 scan |= SCAN_INQUIRY;
1025 else
1026 cancel_delayed_work(&hdev->discov_off);
1027
1028 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1029 if (err < 0)
1030 mgmt_pending_remove(cmd);
1031
Johan Hedberg03811012010-12-08 00:21:06 +02001032 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001033 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001034
1035failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001036 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001037 return err;
1038}
1039
Johan Hedberg406d7802013-03-15 17:07:09 -05001040static void write_fast_connectable(struct hci_request *req, bool enable)
1041{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001042 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001043 struct hci_cp_write_page_scan_activity acp;
1044 u8 type;
1045
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001046 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1047 return;
1048
Johan Hedberg406d7802013-03-15 17:07:09 -05001049 if (enable) {
1050 type = PAGE_SCAN_TYPE_INTERLACED;
1051
1052 /* 160 msec page scan interval */
1053 acp.interval = __constant_cpu_to_le16(0x0100);
1054 } else {
1055 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1056
1057 /* default 1.28 sec page scan */
1058 acp.interval = __constant_cpu_to_le16(0x0800);
1059 }
1060
1061 acp.window = __constant_cpu_to_le16(0x0012);
1062
Johan Hedbergbd98b992013-03-15 17:07:13 -05001063 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1064 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1065 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1066 sizeof(acp), &acp);
1067
1068 if (hdev->page_scan_type != type)
1069 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001070}
1071
Johan Hedberg2b76f452013-03-15 17:07:04 -05001072static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1073{
1074 struct pending_cmd *cmd;
1075
1076 BT_DBG("status 0x%02x", status);
1077
1078 hci_dev_lock(hdev);
1079
1080 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1081 if (!cmd)
1082 goto unlock;
1083
1084 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1085
1086 mgmt_pending_remove(cmd);
1087
1088unlock:
1089 hci_dev_unlock(hdev);
1090}
1091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001092static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001093 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001094{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001095 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001096 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001097 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001098 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001099 int err;
1100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001101 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001102
Johan Hedberge6fe7982013-10-02 15:45:22 +03001103 status = mgmt_bredr_support(hdev);
1104 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001105 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001106 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001107
Johan Hedberga7e80f22013-01-09 16:05:19 +02001108 if (cp->val != 0x00 && cp->val != 0x01)
1109 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1110 MGMT_STATUS_INVALID_PARAMS);
1111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001112 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001113
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001114 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001115 bool changed = false;
1116
1117 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1118 changed = true;
1119
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001120 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001121 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001122 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001123 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1124 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1125 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001126
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001127 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001128 if (err < 0)
1129 goto failed;
1130
1131 if (changed)
1132 err = new_settings(hdev, sk);
1133
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001134 goto failed;
1135 }
1136
1137 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001138 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001139 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001140 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001141 goto failed;
1142 }
1143
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001144 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001145 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001146 goto failed;
1147 }
1148
1149 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1150 if (!cmd) {
1151 err = -ENOMEM;
1152 goto failed;
1153 }
1154
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001155 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001156 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001157 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001158 scan = 0;
1159
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001160 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001161 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001162 cancel_delayed_work(&hdev->discov_off);
1163 }
1164
Johan Hedberg2b76f452013-03-15 17:07:04 -05001165 hci_req_init(&req, hdev);
1166
1167 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1168
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001169 /* If we're going from non-connectable to connectable or
1170 * vice-versa when fast connectable is enabled ensure that fast
1171 * connectable gets disabled. write_fast_connectable won't do
1172 * anything if the page scan parameters are already what they
1173 * should be.
1174 */
1175 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001176 write_fast_connectable(&req, false);
1177
Johan Hedberg2b76f452013-03-15 17:07:04 -05001178 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001179 if (err < 0)
1180 mgmt_pending_remove(cmd);
1181
1182failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001183 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001184 return err;
1185}
1186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001188 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001189{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001190 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001191 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001192 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001194 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001195
Johan Hedberga7e80f22013-01-09 16:05:19 +02001196 if (cp->val != 0x00 && cp->val != 0x01)
1197 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1198 MGMT_STATUS_INVALID_PARAMS);
1199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001200 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001201
1202 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001203 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001204 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001205 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001206
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001207 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001208 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001209 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001210
Marcel Holtmann55594352013-10-06 16:11:57 -07001211 if (changed)
1212 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Marcel Holtmann55594352013-10-06 16:11:57 -07001214unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001215 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001216 return err;
1217}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001218
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001219static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1220 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001221{
1222 struct mgmt_mode *cp = data;
1223 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001224 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001225 int err;
1226
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001227 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001228
Johan Hedberge6fe7982013-10-02 15:45:22 +03001229 status = mgmt_bredr_support(hdev);
1230 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001231 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001232 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001233
Johan Hedberga7e80f22013-01-09 16:05:19 +02001234 if (cp->val != 0x00 && cp->val != 0x01)
1235 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1236 MGMT_STATUS_INVALID_PARAMS);
1237
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001238 hci_dev_lock(hdev);
1239
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001240 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001241 bool changed = false;
1242
1243 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001244 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001245 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1246 changed = true;
1247 }
1248
1249 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1250 if (err < 0)
1251 goto failed;
1252
1253 if (changed)
1254 err = new_settings(hdev, sk);
1255
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001256 goto failed;
1257 }
1258
1259 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001260 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001261 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001262 goto failed;
1263 }
1264
1265 val = !!cp->val;
1266
1267 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1268 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1269 goto failed;
1270 }
1271
1272 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1273 if (!cmd) {
1274 err = -ENOMEM;
1275 goto failed;
1276 }
1277
1278 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1279 if (err < 0) {
1280 mgmt_pending_remove(cmd);
1281 goto failed;
1282 }
1283
1284failed:
1285 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001286 return err;
1287}
1288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001289static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001290{
1291 struct mgmt_mode *cp = data;
1292 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001293 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001294 int err;
1295
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001296 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001297
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001298 status = mgmt_bredr_support(hdev);
1299 if (status)
1300 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1301
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001302 if (!lmp_ssp_capable(hdev))
1303 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1304 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001305
Johan Hedberga7e80f22013-01-09 16:05:19 +02001306 if (cp->val != 0x00 && cp->val != 0x01)
1307 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1308 MGMT_STATUS_INVALID_PARAMS);
1309
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001310 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001311
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001312 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001313 bool changed = false;
1314
1315 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1316 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1317 changed = true;
1318 }
1319
1320 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1321 if (err < 0)
1322 goto failed;
1323
1324 if (changed)
1325 err = new_settings(hdev, sk);
1326
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001327 goto failed;
1328 }
1329
1330 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001331 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1332 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001333 goto failed;
1334 }
1335
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001336 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001337 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1338 goto failed;
1339 }
1340
1341 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1342 if (!cmd) {
1343 err = -ENOMEM;
1344 goto failed;
1345 }
1346
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001347 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001348 if (err < 0) {
1349 mgmt_pending_remove(cmd);
1350 goto failed;
1351 }
1352
1353failed:
1354 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001355 return err;
1356}
1357
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001358static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001359{
1360 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001361 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001362 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001363 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001364
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001365 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001366
Johan Hedberge6fe7982013-10-02 15:45:22 +03001367 status = mgmt_bredr_support(hdev);
1368 if (status)
1369 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001370
Johan Hedberga7e80f22013-01-09 16:05:19 +02001371 if (cp->val != 0x00 && cp->val != 0x01)
1372 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1373 MGMT_STATUS_INVALID_PARAMS);
1374
Marcel Holtmannee392692013-10-01 22:59:23 -07001375 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001376
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001377 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001378 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001379 } else {
1380 if (hdev_is_powered(hdev)) {
1381 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1382 MGMT_STATUS_REJECTED);
1383 goto unlock;
1384 }
1385
Marcel Holtmannee392692013-10-01 22:59:23 -07001386 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001387 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001388
1389 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1390 if (err < 0)
1391 goto unlock;
1392
1393 if (changed)
1394 err = new_settings(hdev, sk);
1395
1396unlock:
1397 hci_dev_unlock(hdev);
1398 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001399}
1400
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001401static void enable_advertising(struct hci_request *req)
1402{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001403 struct hci_dev *hdev = req->hdev;
1404 struct hci_cp_le_set_adv_param cp;
1405 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001406
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001407 memset(&cp, 0, sizeof(cp));
1408 cp.min_interval = __constant_cpu_to_le16(0x0800);
1409 cp.max_interval = __constant_cpu_to_le16(0x0800);
1410 cp.type = LE_ADV_IND;
1411 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1412 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1413 else
1414 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1415 cp.channel_map = 0x07;
1416
1417 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1418
1419 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001420}
1421
1422static void disable_advertising(struct hci_request *req)
1423{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001424 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001425
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001426 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001427}
1428
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001429static void le_enable_complete(struct hci_dev *hdev, u8 status)
1430{
1431 struct cmd_lookup match = { NULL, hdev };
1432
1433 if (status) {
1434 u8 mgmt_err = mgmt_status(status);
1435
1436 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1437 &mgmt_err);
1438 return;
1439 }
1440
1441 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1442
1443 new_settings(hdev, match.sk);
1444
1445 if (match.sk)
1446 sock_put(match.sk);
1447}
1448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001450{
1451 struct mgmt_mode *cp = data;
1452 struct hci_cp_write_le_host_supported hci_cp;
1453 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001454 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001455 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001456 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001457
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001458 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001459
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001460 if (!lmp_le_capable(hdev))
1461 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1462 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001463
Johan Hedberga7e80f22013-01-09 16:05:19 +02001464 if (cp->val != 0x00 && cp->val != 0x01)
1465 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1466 MGMT_STATUS_INVALID_PARAMS);
1467
Johan Hedbergc73eee92013-04-19 18:35:21 +03001468 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001469 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001470 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1471 MGMT_STATUS_REJECTED);
1472
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001473 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001474
1475 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001476 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001477
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001478 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001479 bool changed = false;
1480
1481 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1482 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1483 changed = true;
1484 }
1485
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001486 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1487 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001488 changed = true;
1489 }
1490
Johan Hedberg06199cf2012-02-22 16:37:11 +02001491 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1492 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001493 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001494
1495 if (changed)
1496 err = new_settings(hdev, sk);
1497
Johan Hedberg1de028c2012-02-29 19:55:35 -08001498 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001499 }
1500
Johan Hedberg4375f102013-09-25 13:26:10 +03001501 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1502 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001503 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001504 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001505 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001506 }
1507
1508 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1509 if (!cmd) {
1510 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001511 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001512 }
1513
1514 memset(&hci_cp, 0, sizeof(hci_cp));
1515
1516 if (val) {
1517 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001518 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001519 }
1520
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001521 hci_req_init(&req, hdev);
1522
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001523 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1524 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001525
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001526 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1527 &hci_cp);
1528
1529 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301530 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001531 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001532
Johan Hedberg1de028c2012-02-29 19:55:35 -08001533unlock:
1534 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001535 return err;
1536}
1537
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001538/* This is a helper function to test for pending mgmt commands that can
1539 * cause CoD or EIR HCI commands. We can only allow one such pending
1540 * mgmt command at a time since otherwise we cannot easily track what
1541 * the current values are, will be, and based on that calculate if a new
1542 * HCI command needs to be sent and if yes with what value.
1543 */
1544static bool pending_eir_or_class(struct hci_dev *hdev)
1545{
1546 struct pending_cmd *cmd;
1547
1548 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1549 switch (cmd->opcode) {
1550 case MGMT_OP_ADD_UUID:
1551 case MGMT_OP_REMOVE_UUID:
1552 case MGMT_OP_SET_DEV_CLASS:
1553 case MGMT_OP_SET_POWERED:
1554 return true;
1555 }
1556 }
1557
1558 return false;
1559}
1560
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001561static const u8 bluetooth_base_uuid[] = {
1562 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1563 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1564};
1565
1566static u8 get_uuid_size(const u8 *uuid)
1567{
1568 u32 val;
1569
1570 if (memcmp(uuid, bluetooth_base_uuid, 12))
1571 return 128;
1572
1573 val = get_unaligned_le32(&uuid[12]);
1574 if (val > 0xffff)
1575 return 32;
1576
1577 return 16;
1578}
1579
Johan Hedberg92da6092013-03-15 17:06:55 -05001580static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1581{
1582 struct pending_cmd *cmd;
1583
1584 hci_dev_lock(hdev);
1585
1586 cmd = mgmt_pending_find(mgmt_op, hdev);
1587 if (!cmd)
1588 goto unlock;
1589
1590 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1591 hdev->dev_class, 3);
1592
1593 mgmt_pending_remove(cmd);
1594
1595unlock:
1596 hci_dev_unlock(hdev);
1597}
1598
1599static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1600{
1601 BT_DBG("status 0x%02x", status);
1602
1603 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1604}
1605
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001606static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001607{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001608 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001609 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001610 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001611 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001612 int err;
1613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001614 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001615
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001616 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001617
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001618 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001619 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001620 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001621 goto failed;
1622 }
1623
Andre Guedes92c4c202012-06-07 19:05:44 -03001624 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625 if (!uuid) {
1626 err = -ENOMEM;
1627 goto failed;
1628 }
1629
1630 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001631 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001632 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001633
Johan Hedbergde66aa62013-01-27 00:31:27 +02001634 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001635
Johan Hedberg890ea892013-03-15 17:06:52 -05001636 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001637
Johan Hedberg890ea892013-03-15 17:06:52 -05001638 update_class(&req);
1639 update_eir(&req);
1640
Johan Hedberg92da6092013-03-15 17:06:55 -05001641 err = hci_req_run(&req, add_uuid_complete);
1642 if (err < 0) {
1643 if (err != -ENODATA)
1644 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001646 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001647 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001648 goto failed;
1649 }
1650
1651 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001652 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001653 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001654 goto failed;
1655 }
1656
1657 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001658
1659failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001660 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001661 return err;
1662}
1663
Johan Hedberg24b78d02012-02-23 23:24:30 +02001664static bool enable_service_cache(struct hci_dev *hdev)
1665{
1666 if (!hdev_is_powered(hdev))
1667 return false;
1668
1669 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001670 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1671 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001672 return true;
1673 }
1674
1675 return false;
1676}
1677
Johan Hedberg92da6092013-03-15 17:06:55 -05001678static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1679{
1680 BT_DBG("status 0x%02x", status);
1681
1682 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1683}
1684
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001685static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001686 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001687{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001688 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001689 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001690 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001691 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 -05001692 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001693 int err, found;
1694
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001695 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001697 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001698
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001699 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001700 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001701 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001702 goto unlock;
1703 }
1704
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001705 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1706 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001707
Johan Hedberg24b78d02012-02-23 23:24:30 +02001708 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001709 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001710 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001711 goto unlock;
1712 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001713
Johan Hedberg9246a862012-02-23 21:33:16 +02001714 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001715 }
1716
1717 found = 0;
1718
Johan Hedberg056341c2013-01-27 00:31:30 +02001719 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001720 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1721 continue;
1722
1723 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001724 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001725 found++;
1726 }
1727
1728 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001729 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001731 goto unlock;
1732 }
1733
Johan Hedberg9246a862012-02-23 21:33:16 +02001734update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001735 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001736
Johan Hedberg890ea892013-03-15 17:06:52 -05001737 update_class(&req);
1738 update_eir(&req);
1739
Johan Hedberg92da6092013-03-15 17:06:55 -05001740 err = hci_req_run(&req, remove_uuid_complete);
1741 if (err < 0) {
1742 if (err != -ENODATA)
1743 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001745 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001746 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001747 goto unlock;
1748 }
1749
1750 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001751 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001752 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001753 goto unlock;
1754 }
1755
1756 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001757
1758unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001759 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001760 return err;
1761}
1762
Johan Hedberg92da6092013-03-15 17:06:55 -05001763static void set_class_complete(struct hci_dev *hdev, u8 status)
1764{
1765 BT_DBG("status 0x%02x", status);
1766
1767 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1768}
1769
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001770static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001771 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001772{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001773 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001774 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001775 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001776 int err;
1777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001778 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001779
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001780 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001781 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1782 MGMT_STATUS_NOT_SUPPORTED);
1783
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001784 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001785
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001786 if (pending_eir_or_class(hdev)) {
1787 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1788 MGMT_STATUS_BUSY);
1789 goto unlock;
1790 }
1791
1792 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1793 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1794 MGMT_STATUS_INVALID_PARAMS);
1795 goto unlock;
1796 }
1797
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001798 hdev->major_class = cp->major;
1799 hdev->minor_class = cp->minor;
1800
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001801 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001802 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001803 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001804 goto unlock;
1805 }
1806
Johan Hedberg890ea892013-03-15 17:06:52 -05001807 hci_req_init(&req, hdev);
1808
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001809 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001810 hci_dev_unlock(hdev);
1811 cancel_delayed_work_sync(&hdev->service_cache);
1812 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001813 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001814 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001815
Johan Hedberg890ea892013-03-15 17:06:52 -05001816 update_class(&req);
1817
Johan Hedberg92da6092013-03-15 17:06:55 -05001818 err = hci_req_run(&req, set_class_complete);
1819 if (err < 0) {
1820 if (err != -ENODATA)
1821 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001822
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001823 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001824 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001825 goto unlock;
1826 }
1827
1828 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001829 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001830 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001831 goto unlock;
1832 }
1833
1834 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001835
Johan Hedbergb5235a62012-02-21 14:32:24 +02001836unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001837 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001838 return err;
1839}
1840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001842 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001843{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001844 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001845 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001846 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001847
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001848 BT_DBG("request for %s", hdev->name);
1849
1850 if (!lmp_bredr_capable(hdev))
1851 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1852 MGMT_STATUS_NOT_SUPPORTED);
1853
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001854 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001855
Johan Hedberg86742e12011-11-07 23:13:38 +02001856 expected_len = sizeof(*cp) + key_count *
1857 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001858 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001859 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001860 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001861 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001862 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001863 }
1864
Johan Hedberg4ae14302013-01-20 14:27:13 +02001865 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1866 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1867 MGMT_STATUS_INVALID_PARAMS);
1868
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001869 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001870 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001871
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001872 for (i = 0; i < key_count; i++) {
1873 struct mgmt_link_key_info *key = &cp->keys[i];
1874
1875 if (key->addr.type != BDADDR_BREDR)
1876 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1877 MGMT_STATUS_INVALID_PARAMS);
1878 }
1879
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001880 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001881
1882 hci_link_keys_clear(hdev);
1883
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001884 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001885 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001886 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001887 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001888
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001889 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001890 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001891
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001892 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001893 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001894 }
1895
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001896 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001897
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001898 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001899
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001900 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001901}
1902
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001903static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001904 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001905{
1906 struct mgmt_ev_device_unpaired ev;
1907
1908 bacpy(&ev.addr.bdaddr, bdaddr);
1909 ev.addr.type = addr_type;
1910
1911 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001912 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001913}
1914
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001915static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001916 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001917{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001918 struct mgmt_cp_unpair_device *cp = data;
1919 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001920 struct hci_cp_disconnect dc;
1921 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001922 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001923 int err;
1924
Johan Hedberga8a1d192011-11-10 15:54:38 +02001925 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001926 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1927 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001928
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001929 if (!bdaddr_type_is_valid(cp->addr.type))
1930 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1931 MGMT_STATUS_INVALID_PARAMS,
1932 &rp, sizeof(rp));
1933
Johan Hedberg118da702013-01-20 14:27:20 +02001934 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1935 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1936 MGMT_STATUS_INVALID_PARAMS,
1937 &rp, sizeof(rp));
1938
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001939 hci_dev_lock(hdev);
1940
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001941 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001942 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001943 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001944 goto unlock;
1945 }
1946
Andre Guedes591f47f2012-04-24 21:02:49 -03001947 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001948 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1949 else
1950 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001951
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001952 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001953 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001954 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001955 goto unlock;
1956 }
1957
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001958 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001959 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001960 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001961 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001962 else
1963 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001964 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001965 } else {
1966 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001967 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001968
Johan Hedberga8a1d192011-11-10 15:54:38 +02001969 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001970 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001971 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001972 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001973 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001974 }
1975
Johan Hedberg124f6e32012-02-09 13:50:12 +02001976 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001977 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001978 if (!cmd) {
1979 err = -ENOMEM;
1980 goto unlock;
1981 }
1982
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001983 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001984 dc.reason = 0x13; /* Remote User Terminated Connection */
1985 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1986 if (err < 0)
1987 mgmt_pending_remove(cmd);
1988
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001989unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001990 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001991 return err;
1992}
1993
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001994static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001995 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001996{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001997 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001998 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001999 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002000 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002001 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002002 int err;
2003
2004 BT_DBG("");
2005
Johan Hedberg06a63b12013-01-20 14:27:21 +02002006 memset(&rp, 0, sizeof(rp));
2007 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2008 rp.addr.type = cp->addr.type;
2009
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002010 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002011 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2012 MGMT_STATUS_INVALID_PARAMS,
2013 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002015 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002016
2017 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002018 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2019 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002020 goto failed;
2021 }
2022
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002023 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002024 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2025 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002026 goto failed;
2027 }
2028
Andre Guedes591f47f2012-04-24 21:02:49 -03002029 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002030 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2031 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002032 else
2033 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002034
Vishal Agarwalf9607272012-06-13 05:32:43 +05302035 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002036 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2037 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002038 goto failed;
2039 }
2040
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002041 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002042 if (!cmd) {
2043 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002044 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002045 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002046
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002047 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002048 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002049
2050 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2051 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002052 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002053
2054failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002055 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002056 return err;
2057}
2058
Andre Guedes57c14772012-04-24 21:02:50 -03002059static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002060{
2061 switch (link_type) {
2062 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002063 switch (addr_type) {
2064 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002065 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002066
Johan Hedberg48264f02011-11-09 13:58:58 +02002067 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002068 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002069 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002070 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002071
Johan Hedberg4c659c32011-11-07 23:13:39 +02002072 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002073 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002074 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002075 }
2076}
2077
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002078static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2079 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002080{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002081 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002082 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002083 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002084 int err;
2085 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002086
2087 BT_DBG("");
2088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002090
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002091 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002094 goto unlock;
2095 }
2096
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002097 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002098 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2099 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002100 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002101 }
2102
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002103 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002104 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002105 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002106 err = -ENOMEM;
2107 goto unlock;
2108 }
2109
Johan Hedberg2784eb42011-01-21 13:56:35 +02002110 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002111 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002112 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2113 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002114 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002115 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002116 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002117 continue;
2118 i++;
2119 }
2120
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002121 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002122
Johan Hedberg4c659c32011-11-07 23:13:39 +02002123 /* Recalculate length in case of filtered SCO connections, etc */
2124 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002126 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002127 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002128
Johan Hedberga38528f2011-01-22 06:46:43 +02002129 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002130
2131unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002132 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002133 return err;
2134}
2135
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002136static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002137 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002138{
2139 struct pending_cmd *cmd;
2140 int err;
2141
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002142 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002143 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002144 if (!cmd)
2145 return -ENOMEM;
2146
Johan Hedbergd8457692012-02-17 14:24:57 +02002147 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002148 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002149 if (err < 0)
2150 mgmt_pending_remove(cmd);
2151
2152 return err;
2153}
2154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002155static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002156 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002157{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002158 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002159 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002160 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002161 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002162 int err;
2163
2164 BT_DBG("");
2165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002166 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002167
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002168 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002169 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002170 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002171 goto failed;
2172 }
2173
Johan Hedbergd8457692012-02-17 14:24:57 +02002174 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002175 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002176 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002177 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002178 goto failed;
2179 }
2180
2181 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002182 struct mgmt_cp_pin_code_neg_reply ncp;
2183
2184 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002185
2186 BT_ERR("PIN code is not 16 bytes long");
2187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002189 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002190 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002191 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002192
2193 goto failed;
2194 }
2195
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002196 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002197 if (!cmd) {
2198 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002199 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002200 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002201
Johan Hedbergd8457692012-02-17 14:24:57 +02002202 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002203 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002204 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002205
2206 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2207 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002208 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002209
2210failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002211 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002212 return err;
2213}
2214
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002215static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2216 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002217{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002218 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002219
2220 BT_DBG("");
2221
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002222 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002223
2224 hdev->io_capability = cp->io_capability;
2225
2226 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002227 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002230
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2232 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002233}
2234
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002235static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002236{
2237 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002238 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002239
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002240 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002241 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2242 continue;
2243
Johan Hedberge9a416b2011-02-19 12:05:56 -03002244 if (cmd->user_data != conn)
2245 continue;
2246
2247 return cmd;
2248 }
2249
2250 return NULL;
2251}
2252
2253static void pairing_complete(struct pending_cmd *cmd, u8 status)
2254{
2255 struct mgmt_rp_pair_device rp;
2256 struct hci_conn *conn = cmd->user_data;
2257
Johan Hedbergba4e5642011-11-11 00:07:34 +02002258 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002259 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002260
Johan Hedbergaee9b212012-02-18 15:07:59 +02002261 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002262 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002263
2264 /* So we don't get further callbacks for this connection */
2265 conn->connect_cfm_cb = NULL;
2266 conn->security_cfm_cb = NULL;
2267 conn->disconn_cfm_cb = NULL;
2268
David Herrmann76a68ba2013-04-06 20:28:37 +02002269 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002270
Johan Hedberga664b5b2011-02-19 12:06:02 -03002271 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002272}
2273
2274static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2275{
2276 struct pending_cmd *cmd;
2277
2278 BT_DBG("status %u", status);
2279
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002280 cmd = find_pairing(conn);
2281 if (!cmd)
2282 BT_DBG("Unable to find a pending command");
2283 else
Johan Hedberge2113262012-02-18 15:20:03 +02002284 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002285}
2286
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302287static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2288{
2289 struct pending_cmd *cmd;
2290
2291 BT_DBG("status %u", status);
2292
2293 if (!status)
2294 return;
2295
2296 cmd = find_pairing(conn);
2297 if (!cmd)
2298 BT_DBG("Unable to find a pending command");
2299 else
2300 pairing_complete(cmd, mgmt_status(status));
2301}
2302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002303static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002306 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002307 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002308 struct pending_cmd *cmd;
2309 u8 sec_level, auth_type;
2310 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002311 int err;
2312
2313 BT_DBG("");
2314
Szymon Jancf950a30e2013-01-18 12:48:07 +01002315 memset(&rp, 0, sizeof(rp));
2316 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2317 rp.addr.type = cp->addr.type;
2318
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002319 if (!bdaddr_type_is_valid(cp->addr.type))
2320 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2321 MGMT_STATUS_INVALID_PARAMS,
2322 &rp, sizeof(rp));
2323
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002324 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002325
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002326 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002327 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2328 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002329 goto unlock;
2330 }
2331
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002332 sec_level = BT_SECURITY_MEDIUM;
2333 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002334 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002335 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002336 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002337
Andre Guedes591f47f2012-04-24 21:02:49 -03002338 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002339 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2340 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002341 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002342 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2343 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002344
Ville Tervo30e76272011-02-22 16:10:53 -03002345 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002346 int status;
2347
2348 if (PTR_ERR(conn) == -EBUSY)
2349 status = MGMT_STATUS_BUSY;
2350 else
2351 status = MGMT_STATUS_CONNECT_FAILED;
2352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002353 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002354 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002355 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002356 goto unlock;
2357 }
2358
2359 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002360 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002361 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002362 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002363 goto unlock;
2364 }
2365
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002366 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002367 if (!cmd) {
2368 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002369 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002370 goto unlock;
2371 }
2372
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002373 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002374 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002375 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302376 else
2377 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002378
Johan Hedberge9a416b2011-02-19 12:05:56 -03002379 conn->security_cfm_cb = pairing_complete_cb;
2380 conn->disconn_cfm_cb = pairing_complete_cb;
2381 conn->io_capability = cp->io_cap;
2382 cmd->user_data = conn;
2383
2384 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002385 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002386 pairing_complete(cmd, 0);
2387
2388 err = 0;
2389
2390unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002391 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002392 return err;
2393}
2394
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002395static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2396 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002397{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002398 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002399 struct pending_cmd *cmd;
2400 struct hci_conn *conn;
2401 int err;
2402
2403 BT_DBG("");
2404
Johan Hedberg28424702012-02-02 04:02:29 +02002405 hci_dev_lock(hdev);
2406
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002407 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002408 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002409 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002410 goto unlock;
2411 }
2412
Johan Hedberg28424702012-02-02 04:02:29 +02002413 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2414 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002415 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002417 goto unlock;
2418 }
2419
2420 conn = cmd->user_data;
2421
2422 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002423 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002425 goto unlock;
2426 }
2427
2428 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2429
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002430 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002431 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002432unlock:
2433 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002434 return err;
2435}
2436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002437static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002438 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002439 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002440{
Johan Hedberga5c29682011-02-19 12:05:57 -03002441 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002442 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002443 int err;
2444
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002445 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002446
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002447 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002448 err = cmd_complete(sk, hdev->id, mgmt_op,
2449 MGMT_STATUS_NOT_POWERED, addr,
2450 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002451 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002452 }
2453
Johan Hedberg1707c602013-03-15 17:07:15 -05002454 if (addr->type == BDADDR_BREDR)
2455 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002456 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002457 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002458
Johan Hedberg272d90d2012-02-09 15:26:12 +02002459 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002460 err = cmd_complete(sk, hdev->id, mgmt_op,
2461 MGMT_STATUS_NOT_CONNECTED, addr,
2462 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002463 goto done;
2464 }
2465
Johan Hedberg1707c602013-03-15 17:07:15 -05002466 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002467 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002468 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002469
Brian Gix5fe57d92011-12-21 16:12:13 -08002470 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002471 err = cmd_complete(sk, hdev->id, mgmt_op,
2472 MGMT_STATUS_SUCCESS, addr,
2473 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002474 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002475 err = cmd_complete(sk, hdev->id, mgmt_op,
2476 MGMT_STATUS_FAILED, addr,
2477 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002478
Brian Gix47c15e22011-11-16 13:53:14 -08002479 goto done;
2480 }
2481
Johan Hedberg1707c602013-03-15 17:07:15 -05002482 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002483 if (!cmd) {
2484 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002485 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002486 }
2487
Brian Gix0df4c182011-11-16 13:53:13 -08002488 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002489 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2490 struct hci_cp_user_passkey_reply cp;
2491
Johan Hedberg1707c602013-03-15 17:07:15 -05002492 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002493 cp.passkey = passkey;
2494 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2495 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002496 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2497 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002498
Johan Hedberga664b5b2011-02-19 12:06:02 -03002499 if (err < 0)
2500 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002501
Brian Gix0df4c182011-11-16 13:53:13 -08002502done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002503 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002504 return err;
2505}
2506
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302507static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2508 void *data, u16 len)
2509{
2510 struct mgmt_cp_pin_code_neg_reply *cp = data;
2511
2512 BT_DBG("");
2513
Johan Hedberg1707c602013-03-15 17:07:15 -05002514 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302515 MGMT_OP_PIN_CODE_NEG_REPLY,
2516 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2517}
2518
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002519static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2520 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002521{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002522 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002523
2524 BT_DBG("");
2525
2526 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002527 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002528 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002529
Johan Hedberg1707c602013-03-15 17:07:15 -05002530 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002531 MGMT_OP_USER_CONFIRM_REPLY,
2532 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002533}
2534
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002535static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002537{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002538 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002539
2540 BT_DBG("");
2541
Johan Hedberg1707c602013-03-15 17:07:15 -05002542 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002543 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2544 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002545}
2546
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2548 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002549{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002550 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002551
2552 BT_DBG("");
2553
Johan Hedberg1707c602013-03-15 17:07:15 -05002554 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 MGMT_OP_USER_PASSKEY_REPLY,
2556 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002557}
2558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002559static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002560 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002561{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002562 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002563
2564 BT_DBG("");
2565
Johan Hedberg1707c602013-03-15 17:07:15 -05002566 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002567 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2568 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002569}
2570
Johan Hedberg13928972013-03-15 17:07:00 -05002571static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002572{
Johan Hedberg13928972013-03-15 17:07:00 -05002573 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002574 struct hci_cp_write_local_name cp;
2575
Johan Hedberg13928972013-03-15 17:07:00 -05002576 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002577
Johan Hedberg890ea892013-03-15 17:06:52 -05002578 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002579}
2580
Johan Hedberg13928972013-03-15 17:07:00 -05002581static void set_name_complete(struct hci_dev *hdev, u8 status)
2582{
2583 struct mgmt_cp_set_local_name *cp;
2584 struct pending_cmd *cmd;
2585
2586 BT_DBG("status 0x%02x", status);
2587
2588 hci_dev_lock(hdev);
2589
2590 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2591 if (!cmd)
2592 goto unlock;
2593
2594 cp = cmd->param;
2595
2596 if (status)
2597 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2598 mgmt_status(status));
2599 else
2600 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2601 cp, sizeof(*cp));
2602
2603 mgmt_pending_remove(cmd);
2604
2605unlock:
2606 hci_dev_unlock(hdev);
2607}
2608
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002609static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002610 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002611{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002612 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002613 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002614 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002615 int err;
2616
2617 BT_DBG("");
2618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002619 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002620
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002621 /* If the old values are the same as the new ones just return a
2622 * direct command complete event.
2623 */
2624 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2625 !memcmp(hdev->short_name, cp->short_name,
2626 sizeof(hdev->short_name))) {
2627 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2628 data, len);
2629 goto failed;
2630 }
2631
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002632 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002633
Johan Hedbergb5235a62012-02-21 14:32:24 +02002634 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002635 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002636
2637 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002639 if (err < 0)
2640 goto failed;
2641
2642 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002643 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002644
Johan Hedbergb5235a62012-02-21 14:32:24 +02002645 goto failed;
2646 }
2647
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002648 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002649 if (!cmd) {
2650 err = -ENOMEM;
2651 goto failed;
2652 }
2653
Johan Hedberg13928972013-03-15 17:07:00 -05002654 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2655
Johan Hedberg890ea892013-03-15 17:06:52 -05002656 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002657
2658 if (lmp_bredr_capable(hdev)) {
2659 update_name(&req);
2660 update_eir(&req);
2661 }
2662
2663 if (lmp_le_capable(hdev))
2664 hci_update_ad(&req);
2665
Johan Hedberg13928972013-03-15 17:07:00 -05002666 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002667 if (err < 0)
2668 mgmt_pending_remove(cmd);
2669
2670failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002671 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002672 return err;
2673}
2674
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002675static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002676 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002677{
Szymon Jancc35938b2011-03-22 13:12:21 +01002678 struct pending_cmd *cmd;
2679 int err;
2680
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002681 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002682
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002683 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002684
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002685 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002686 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002687 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002688 goto unlock;
2689 }
2690
Andre Guedes9a1a1992012-07-24 15:03:48 -03002691 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002692 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002693 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002694 goto unlock;
2695 }
2696
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002697 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002700 goto unlock;
2701 }
2702
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002703 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002704 if (!cmd) {
2705 err = -ENOMEM;
2706 goto unlock;
2707 }
2708
2709 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2710 if (err < 0)
2711 mgmt_pending_remove(cmd);
2712
2713unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002714 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002715 return err;
2716}
2717
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002718static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002719 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002720{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002721 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002722 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002723 int err;
2724
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002725 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002726
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002727 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002728
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002729 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002730 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002731 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002732 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002733 else
Szymon Janca6785be2012-12-13 15:11:21 +01002734 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002736 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002737 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002738
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002739 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002740 return err;
2741}
2742
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002743static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002744 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002745{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002746 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002747 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002748 int err;
2749
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002750 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002752 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002753
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002754 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002755 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002756 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002757 else
Szymon Janca6785be2012-12-13 15:11:21 +01002758 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002762
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002763 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002764 return err;
2765}
2766
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002767static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2768{
2769 struct pending_cmd *cmd;
2770 u8 type;
2771 int err;
2772
2773 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2774
2775 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2776 if (!cmd)
2777 return -ENOENT;
2778
2779 type = hdev->discovery.type;
2780
2781 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2782 &type, sizeof(type));
2783 mgmt_pending_remove(cmd);
2784
2785 return err;
2786}
2787
Andre Guedes7c307722013-04-30 15:29:28 -03002788static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2789{
2790 BT_DBG("status %d", status);
2791
2792 if (status) {
2793 hci_dev_lock(hdev);
2794 mgmt_start_discovery_failed(hdev, status);
2795 hci_dev_unlock(hdev);
2796 return;
2797 }
2798
2799 hci_dev_lock(hdev);
2800 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2801 hci_dev_unlock(hdev);
2802
2803 switch (hdev->discovery.type) {
2804 case DISCOV_TYPE_LE:
2805 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002806 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002807 break;
2808
2809 case DISCOV_TYPE_INTERLEAVED:
2810 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002811 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002812 break;
2813
2814 case DISCOV_TYPE_BREDR:
2815 break;
2816
2817 default:
2818 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2819 }
2820}
2821
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002822static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002823 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002824{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002825 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002826 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002827 struct hci_cp_le_set_scan_param param_cp;
2828 struct hci_cp_le_set_scan_enable enable_cp;
2829 struct hci_cp_inquiry inq_cp;
2830 struct hci_request req;
2831 /* General inquiry access code (GIAC) */
2832 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002833 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002834 int err;
2835
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002836 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002837
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002838 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002839
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002840 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002841 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002842 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002843 goto failed;
2844 }
2845
Andre Guedes642be6c2012-03-21 00:03:37 -03002846 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2847 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2848 MGMT_STATUS_BUSY);
2849 goto failed;
2850 }
2851
Johan Hedbergff9ef572012-01-04 14:23:45 +02002852 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002853 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002854 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002855 goto failed;
2856 }
2857
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002858 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002859 if (!cmd) {
2860 err = -ENOMEM;
2861 goto failed;
2862 }
2863
Andre Guedes4aab14e2012-02-17 20:39:36 -03002864 hdev->discovery.type = cp->type;
2865
Andre Guedes7c307722013-04-30 15:29:28 -03002866 hci_req_init(&req, hdev);
2867
Andre Guedes4aab14e2012-02-17 20:39:36 -03002868 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002869 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002870 status = mgmt_bredr_support(hdev);
2871 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002872 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002873 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002874 mgmt_pending_remove(cmd);
2875 goto failed;
2876 }
2877
Andre Guedes7c307722013-04-30 15:29:28 -03002878 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2879 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2880 MGMT_STATUS_BUSY);
2881 mgmt_pending_remove(cmd);
2882 goto failed;
2883 }
2884
2885 hci_inquiry_cache_flush(hdev);
2886
2887 memset(&inq_cp, 0, sizeof(inq_cp));
2888 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002889 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002890 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002891 break;
2892
2893 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002894 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002895 status = mgmt_le_support(hdev);
2896 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002897 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002898 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002899 mgmt_pending_remove(cmd);
2900 goto failed;
2901 }
2902
Andre Guedes7c307722013-04-30 15:29:28 -03002903 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002904 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002905 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2906 MGMT_STATUS_NOT_SUPPORTED);
2907 mgmt_pending_remove(cmd);
2908 goto failed;
2909 }
2910
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002911 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002912 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2913 MGMT_STATUS_REJECTED);
2914 mgmt_pending_remove(cmd);
2915 goto failed;
2916 }
2917
2918 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2919 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2920 MGMT_STATUS_BUSY);
2921 mgmt_pending_remove(cmd);
2922 goto failed;
2923 }
2924
2925 memset(&param_cp, 0, sizeof(param_cp));
2926 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002927 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2928 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002929 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2930 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2931 else
2932 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002933 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2934 &param_cp);
2935
2936 memset(&enable_cp, 0, sizeof(enable_cp));
2937 enable_cp.enable = LE_SCAN_ENABLE;
2938 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2939 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2940 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002941 break;
2942
Andre Guedesf39799f2012-02-17 20:39:35 -03002943 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002944 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2945 MGMT_STATUS_INVALID_PARAMS);
2946 mgmt_pending_remove(cmd);
2947 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002948 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002949
Andre Guedes7c307722013-04-30 15:29:28 -03002950 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002951 if (err < 0)
2952 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002953 else
2954 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002955
2956failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002957 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002958 return err;
2959}
2960
Andre Guedes1183fdc2013-04-30 15:29:35 -03002961static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2962{
2963 struct pending_cmd *cmd;
2964 int err;
2965
2966 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2967 if (!cmd)
2968 return -ENOENT;
2969
2970 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2971 &hdev->discovery.type, sizeof(hdev->discovery.type));
2972 mgmt_pending_remove(cmd);
2973
2974 return err;
2975}
2976
Andre Guedes0e05bba2013-04-30 15:29:33 -03002977static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2978{
2979 BT_DBG("status %d", status);
2980
2981 hci_dev_lock(hdev);
2982
2983 if (status) {
2984 mgmt_stop_discovery_failed(hdev, status);
2985 goto unlock;
2986 }
2987
2988 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2989
2990unlock:
2991 hci_dev_unlock(hdev);
2992}
2993
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002994static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002995 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002996{
Johan Hedbergd9306502012-02-20 23:25:18 +02002997 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002998 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002999 struct hci_cp_remote_name_req_cancel cp;
3000 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003001 struct hci_request req;
3002 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003003 int err;
3004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003005 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003006
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003007 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003008
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003009 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003010 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3012 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003013 goto unlock;
3014 }
3015
3016 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003017 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3019 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003020 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003021 }
3022
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003023 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003024 if (!cmd) {
3025 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003026 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003027 }
3028
Andre Guedes0e05bba2013-04-30 15:29:33 -03003029 hci_req_init(&req, hdev);
3030
Andre Guedese0d9727e2012-03-20 15:15:36 -03003031 switch (hdev->discovery.state) {
3032 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003033 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3034 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3035 } else {
3036 cancel_delayed_work(&hdev->le_scan_disable);
3037
3038 memset(&enable_cp, 0, sizeof(enable_cp));
3039 enable_cp.enable = LE_SCAN_DISABLE;
3040 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3041 sizeof(enable_cp), &enable_cp);
3042 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003043
Andre Guedese0d9727e2012-03-20 15:15:36 -03003044 break;
3045
3046 case DISCOVERY_RESOLVING:
3047 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003048 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003049 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003050 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003051 err = cmd_complete(sk, hdev->id,
3052 MGMT_OP_STOP_DISCOVERY, 0,
3053 &mgmt_cp->type,
3054 sizeof(mgmt_cp->type));
3055 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3056 goto unlock;
3057 }
3058
3059 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003060 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3061 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003062
3063 break;
3064
3065 default:
3066 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003067
3068 mgmt_pending_remove(cmd);
3069 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3070 MGMT_STATUS_FAILED, &mgmt_cp->type,
3071 sizeof(mgmt_cp->type));
3072 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003073 }
3074
Andre Guedes0e05bba2013-04-30 15:29:33 -03003075 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003076 if (err < 0)
3077 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003078 else
3079 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003080
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003081unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003082 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003083 return err;
3084}
3085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003089 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003090 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003091 int err;
3092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003093 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003094
Johan Hedberg561aafb2012-01-04 13:31:59 +02003095 hci_dev_lock(hdev);
3096
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003097 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003098 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003099 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003100 goto failed;
3101 }
3102
Johan Hedberga198e7b2012-02-17 14:27:06 +02003103 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003104 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003105 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003106 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003107 goto failed;
3108 }
3109
3110 if (cp->name_known) {
3111 e->name_state = NAME_KNOWN;
3112 list_del(&e->list);
3113 } else {
3114 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003115 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003116 }
3117
Johan Hedberge3846622013-01-09 15:29:33 +02003118 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3119 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003120
3121failed:
3122 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003123 return err;
3124}
3125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003126static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003128{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003129 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003130 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003131 int err;
3132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003133 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003134
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003135 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003136 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3137 MGMT_STATUS_INVALID_PARAMS,
3138 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003139
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003140 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003141
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003142 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003143 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003144 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003145 else
Szymon Janca6785be2012-12-13 15:11:21 +01003146 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003147
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003148 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003149 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003151 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003152
3153 return err;
3154}
3155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003156static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003157 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003158{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003159 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003160 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003161 int err;
3162
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003163 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003164
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003165 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003166 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3167 MGMT_STATUS_INVALID_PARAMS,
3168 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003169
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003170 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003171
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003172 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003173 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003174 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003175 else
Szymon Janca6785be2012-12-13 15:11:21 +01003176 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003178 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003179 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003181 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003182
3183 return err;
3184}
3185
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003186static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3187 u16 len)
3188{
3189 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003190 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003191 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003192 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003193
3194 BT_DBG("%s", hdev->name);
3195
Szymon Jancc72d4b82012-03-16 16:02:57 +01003196 source = __le16_to_cpu(cp->source);
3197
3198 if (source > 0x0002)
3199 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3200 MGMT_STATUS_INVALID_PARAMS);
3201
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003202 hci_dev_lock(hdev);
3203
Szymon Jancc72d4b82012-03-16 16:02:57 +01003204 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003205 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3206 hdev->devid_product = __le16_to_cpu(cp->product);
3207 hdev->devid_version = __le16_to_cpu(cp->version);
3208
3209 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3210
Johan Hedberg890ea892013-03-15 17:06:52 -05003211 hci_req_init(&req, hdev);
3212 update_eir(&req);
3213 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003214
3215 hci_dev_unlock(hdev);
3216
3217 return err;
3218}
3219
Johan Hedberg4375f102013-09-25 13:26:10 +03003220static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3221{
3222 struct cmd_lookup match = { NULL, hdev };
3223
3224 if (status) {
3225 u8 mgmt_err = mgmt_status(status);
3226
3227 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3228 cmd_status_rsp, &mgmt_err);
3229 return;
3230 }
3231
3232 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3233 &match);
3234
3235 new_settings(hdev, match.sk);
3236
3237 if (match.sk)
3238 sock_put(match.sk);
3239}
3240
3241static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3242{
3243 struct mgmt_mode *cp = data;
3244 struct pending_cmd *cmd;
3245 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003246 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003247 int err;
3248
3249 BT_DBG("request for %s", hdev->name);
3250
Johan Hedberge6fe7982013-10-02 15:45:22 +03003251 status = mgmt_le_support(hdev);
3252 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003253 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003254 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003255
3256 if (cp->val != 0x00 && cp->val != 0x01)
3257 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3258 MGMT_STATUS_INVALID_PARAMS);
3259
3260 hci_dev_lock(hdev);
3261
3262 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003263 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003264
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003265 /* The following conditions are ones which mean that we should
3266 * not do any HCI communication but directly send a mgmt
3267 * response to user space (after toggling the flag if
3268 * necessary).
3269 */
3270 if (!hdev_is_powered(hdev) || val == enabled ||
3271 hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECTED)) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003272 bool changed = false;
3273
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003274 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3275 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003276 changed = true;
3277 }
3278
3279 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3280 if (err < 0)
3281 goto unlock;
3282
3283 if (changed)
3284 err = new_settings(hdev, sk);
3285
3286 goto unlock;
3287 }
3288
3289 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3290 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3291 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3292 MGMT_STATUS_BUSY);
3293 goto unlock;
3294 }
3295
3296 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3297 if (!cmd) {
3298 err = -ENOMEM;
3299 goto unlock;
3300 }
3301
3302 hci_req_init(&req, hdev);
3303
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003304 if (val)
3305 enable_advertising(&req);
3306 else
3307 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003308
3309 err = hci_req_run(&req, set_advertising_complete);
3310 if (err < 0)
3311 mgmt_pending_remove(cmd);
3312
3313unlock:
3314 hci_dev_unlock(hdev);
3315 return err;
3316}
3317
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003318static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3319 void *data, u16 len)
3320{
3321 struct mgmt_cp_set_static_address *cp = data;
3322 int err;
3323
3324 BT_DBG("%s", hdev->name);
3325
Marcel Holtmann62af4442013-10-02 22:10:32 -07003326 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003327 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003328 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003329
3330 if (hdev_is_powered(hdev))
3331 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3332 MGMT_STATUS_REJECTED);
3333
3334 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3335 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3336 return cmd_status(sk, hdev->id,
3337 MGMT_OP_SET_STATIC_ADDRESS,
3338 MGMT_STATUS_INVALID_PARAMS);
3339
3340 /* Two most significant bits shall be set */
3341 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3342 return cmd_status(sk, hdev->id,
3343 MGMT_OP_SET_STATIC_ADDRESS,
3344 MGMT_STATUS_INVALID_PARAMS);
3345 }
3346
3347 hci_dev_lock(hdev);
3348
3349 bacpy(&hdev->static_addr, &cp->bdaddr);
3350
3351 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3352
3353 hci_dev_unlock(hdev);
3354
3355 return err;
3356}
3357
Johan Hedberg33e38b32013-03-15 17:07:05 -05003358static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3359{
3360 struct pending_cmd *cmd;
3361
3362 BT_DBG("status 0x%02x", status);
3363
3364 hci_dev_lock(hdev);
3365
3366 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3367 if (!cmd)
3368 goto unlock;
3369
3370 if (status) {
3371 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3372 mgmt_status(status));
3373 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003374 struct mgmt_mode *cp = cmd->param;
3375
3376 if (cp->val)
3377 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3378 else
3379 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3380
Johan Hedberg33e38b32013-03-15 17:07:05 -05003381 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3382 new_settings(hdev, cmd->sk);
3383 }
3384
3385 mgmt_pending_remove(cmd);
3386
3387unlock:
3388 hci_dev_unlock(hdev);
3389}
3390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003391static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003392 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003393{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003394 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003395 struct pending_cmd *cmd;
3396 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003397 int err;
3398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003399 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003400
Johan Hedberg56f87902013-10-02 13:43:13 +03003401 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3402 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003403 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3404 MGMT_STATUS_NOT_SUPPORTED);
3405
Johan Hedberga7e80f22013-01-09 16:05:19 +02003406 if (cp->val != 0x00 && cp->val != 0x01)
3407 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3408 MGMT_STATUS_INVALID_PARAMS);
3409
Johan Hedberg5400c042012-02-21 16:40:33 +02003410 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003411 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003412 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003413
3414 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003415 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003416 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003417
3418 hci_dev_lock(hdev);
3419
Johan Hedberg05cbf292013-03-15 17:07:07 -05003420 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3421 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3422 MGMT_STATUS_BUSY);
3423 goto unlock;
3424 }
3425
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003426 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3427 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3428 hdev);
3429 goto unlock;
3430 }
3431
Johan Hedberg33e38b32013-03-15 17:07:05 -05003432 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3433 data, len);
3434 if (!cmd) {
3435 err = -ENOMEM;
3436 goto unlock;
3437 }
3438
3439 hci_req_init(&req, hdev);
3440
Johan Hedberg406d7802013-03-15 17:07:09 -05003441 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003442
3443 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003444 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003445 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003446 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003447 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003448 }
3449
Johan Hedberg33e38b32013-03-15 17:07:05 -05003450unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003451 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003452
Antti Julkuf6422ec2011-06-22 13:11:56 +03003453 return err;
3454}
3455
Johan Hedberg0663ca22013-10-02 13:43:14 +03003456static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3457{
3458 struct pending_cmd *cmd;
3459
3460 BT_DBG("status 0x%02x", status);
3461
3462 hci_dev_lock(hdev);
3463
3464 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3465 if (!cmd)
3466 goto unlock;
3467
3468 if (status) {
3469 u8 mgmt_err = mgmt_status(status);
3470
3471 /* We need to restore the flag if related HCI commands
3472 * failed.
3473 */
3474 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3475
3476 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3477 } else {
3478 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3479 new_settings(hdev, cmd->sk);
3480 }
3481
3482 mgmt_pending_remove(cmd);
3483
3484unlock:
3485 hci_dev_unlock(hdev);
3486}
3487
3488static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3489{
3490 struct mgmt_mode *cp = data;
3491 struct pending_cmd *cmd;
3492 struct hci_request req;
3493 int err;
3494
3495 BT_DBG("request for %s", hdev->name);
3496
3497 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3498 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3499 MGMT_STATUS_NOT_SUPPORTED);
3500
3501 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3502 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3503 MGMT_STATUS_REJECTED);
3504
3505 if (cp->val != 0x00 && cp->val != 0x01)
3506 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3507 MGMT_STATUS_INVALID_PARAMS);
3508
3509 hci_dev_lock(hdev);
3510
3511 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3512 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3513 goto unlock;
3514 }
3515
3516 if (!hdev_is_powered(hdev)) {
3517 if (!cp->val) {
3518 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3519 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3520 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3521 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3522 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3523 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3524 }
3525
3526 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3527
3528 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3529 if (err < 0)
3530 goto unlock;
3531
3532 err = new_settings(hdev, sk);
3533 goto unlock;
3534 }
3535
3536 /* Reject disabling when powered on */
3537 if (!cp->val) {
3538 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3539 MGMT_STATUS_REJECTED);
3540 goto unlock;
3541 }
3542
3543 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3544 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3545 MGMT_STATUS_BUSY);
3546 goto unlock;
3547 }
3548
3549 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3550 if (!cmd) {
3551 err = -ENOMEM;
3552 goto unlock;
3553 }
3554
3555 /* We need to flip the bit already here so that hci_update_ad
3556 * generates the correct flags.
3557 */
3558 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3559
3560 hci_req_init(&req, hdev);
3561 hci_update_ad(&req);
3562 err = hci_req_run(&req, set_bredr_complete);
3563 if (err < 0)
3564 mgmt_pending_remove(cmd);
3565
3566unlock:
3567 hci_dev_unlock(hdev);
3568 return err;
3569}
3570
Johan Hedberg3f706b72013-01-20 14:27:16 +02003571static bool ltk_is_valid(struct mgmt_ltk_info *key)
3572{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003573 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3574 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003575 if (key->master != 0x00 && key->master != 0x01)
3576 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003577 if (!bdaddr_type_is_le(key->addr.type))
3578 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003579 return true;
3580}
3581
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003582static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003583 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003584{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003585 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3586 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003587 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003588
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003589 BT_DBG("request for %s", hdev->name);
3590
3591 if (!lmp_le_capable(hdev))
3592 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3593 MGMT_STATUS_NOT_SUPPORTED);
3594
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003595 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003596
3597 expected_len = sizeof(*cp) + key_count *
3598 sizeof(struct mgmt_ltk_info);
3599 if (expected_len != len) {
3600 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003601 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003602 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003603 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003604 }
3605
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003606 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003607
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003608 for (i = 0; i < key_count; i++) {
3609 struct mgmt_ltk_info *key = &cp->keys[i];
3610
Johan Hedberg3f706b72013-01-20 14:27:16 +02003611 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003612 return cmd_status(sk, hdev->id,
3613 MGMT_OP_LOAD_LONG_TERM_KEYS,
3614 MGMT_STATUS_INVALID_PARAMS);
3615 }
3616
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003617 hci_dev_lock(hdev);
3618
3619 hci_smp_ltks_clear(hdev);
3620
3621 for (i = 0; i < key_count; i++) {
3622 struct mgmt_ltk_info *key = &cp->keys[i];
3623 u8 type;
3624
3625 if (key->master)
3626 type = HCI_SMP_LTK;
3627 else
3628 type = HCI_SMP_LTK_SLAVE;
3629
Hemant Gupta4596fde2012-04-16 14:57:40 +05303630 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003631 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003632 type, 0, key->authenticated, key->val,
3633 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003634 }
3635
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003636 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3637 NULL, 0);
3638
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003639 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003640
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003641 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003642}
3643
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003644static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003645 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3646 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003647 bool var_len;
3648 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003649} mgmt_handlers[] = {
3650 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003651 { read_version, false, MGMT_READ_VERSION_SIZE },
3652 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3653 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3654 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3655 { set_powered, false, MGMT_SETTING_SIZE },
3656 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3657 { set_connectable, false, MGMT_SETTING_SIZE },
3658 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3659 { set_pairable, false, MGMT_SETTING_SIZE },
3660 { set_link_security, false, MGMT_SETTING_SIZE },
3661 { set_ssp, false, MGMT_SETTING_SIZE },
3662 { set_hs, false, MGMT_SETTING_SIZE },
3663 { set_le, false, MGMT_SETTING_SIZE },
3664 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3665 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3666 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3667 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3668 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3669 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3670 { disconnect, false, MGMT_DISCONNECT_SIZE },
3671 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3672 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3673 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3674 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3675 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3676 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3677 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3678 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3679 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3680 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3681 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3682 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3683 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3684 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3685 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3686 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3687 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3688 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3689 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003690 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003691 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003692 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003693 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003694};
3695
3696
Johan Hedberg03811012010-12-08 00:21:06 +02003697int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3698{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003699 void *buf;
3700 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003701 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003702 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003703 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003704 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003705 int err;
3706
3707 BT_DBG("got %zu bytes", msglen);
3708
3709 if (msglen < sizeof(*hdr))
3710 return -EINVAL;
3711
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003712 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003713 if (!buf)
3714 return -ENOMEM;
3715
3716 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3717 err = -EFAULT;
3718 goto done;
3719 }
3720
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003721 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003722 opcode = __le16_to_cpu(hdr->opcode);
3723 index = __le16_to_cpu(hdr->index);
3724 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003725
3726 if (len != msglen - sizeof(*hdr)) {
3727 err = -EINVAL;
3728 goto done;
3729 }
3730
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003731 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003732 hdev = hci_dev_get(index);
3733 if (!hdev) {
3734 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003735 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003736 goto done;
3737 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003738
3739 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3740 err = cmd_status(sk, index, opcode,
3741 MGMT_STATUS_INVALID_INDEX);
3742 goto done;
3743 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003744 }
3745
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003746 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003747 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003748 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003749 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003750 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003751 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003752 }
3753
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003754 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003755 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003756 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003757 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003758 goto done;
3759 }
3760
Johan Hedbergbe22b542012-03-01 22:24:41 +02003761 handler = &mgmt_handlers[opcode];
3762
3763 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003764 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003765 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003766 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003767 goto done;
3768 }
3769
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003770 if (hdev)
3771 mgmt_init_hdev(sk, hdev);
3772
3773 cp = buf + sizeof(*hdr);
3774
Johan Hedbergbe22b542012-03-01 22:24:41 +02003775 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003776 if (err < 0)
3777 goto done;
3778
Johan Hedberg03811012010-12-08 00:21:06 +02003779 err = msglen;
3780
3781done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003782 if (hdev)
3783 hci_dev_put(hdev);
3784
Johan Hedberg03811012010-12-08 00:21:06 +02003785 kfree(buf);
3786 return err;
3787}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003788
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003789void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003790{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003791 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003792 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003793
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003794 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003795}
3796
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003797void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003798{
Johan Hedberg5f159032012-03-02 03:13:19 +02003799 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003800
Marcel Holtmann1514b892013-10-06 08:25:01 -07003801 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003802 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003803
Johan Hedberg744cf192011-11-08 20:40:14 +02003804 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003805
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003806 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003807}
3808
Johan Hedberg890ea892013-03-15 17:06:52 -05003809static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003810{
Johan Hedberg890ea892013-03-15 17:06:52 -05003811 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003812 u8 scan = 0;
3813
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003814 /* Ensure that fast connectable is disabled. This function will
3815 * not do anything if the page scan parameters are already what
3816 * they should be.
3817 */
3818 write_fast_connectable(req, false);
3819
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003820 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3821 scan |= SCAN_PAGE;
3822 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3823 scan |= SCAN_INQUIRY;
3824
Johan Hedberg890ea892013-03-15 17:06:52 -05003825 if (scan)
3826 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003827}
3828
Johan Hedberg229ab392013-03-15 17:06:53 -05003829static void powered_complete(struct hci_dev *hdev, u8 status)
3830{
3831 struct cmd_lookup match = { NULL, hdev };
3832
3833 BT_DBG("status 0x%02x", status);
3834
3835 hci_dev_lock(hdev);
3836
3837 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3838
3839 new_settings(hdev, match.sk);
3840
3841 hci_dev_unlock(hdev);
3842
3843 if (match.sk)
3844 sock_put(match.sk);
3845}
3846
Johan Hedberg70da6242013-03-15 17:06:51 -05003847static int powered_update_hci(struct hci_dev *hdev)
3848{
Johan Hedberg890ea892013-03-15 17:06:52 -05003849 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003850 u8 link_sec;
3851
Johan Hedberg890ea892013-03-15 17:06:52 -05003852 hci_req_init(&req, hdev);
3853
Johan Hedberg70da6242013-03-15 17:06:51 -05003854 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3855 !lmp_host_ssp_capable(hdev)) {
3856 u8 ssp = 1;
3857
Johan Hedberg890ea892013-03-15 17:06:52 -05003858 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003859 }
3860
Johan Hedbergc73eee92013-04-19 18:35:21 +03003861 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3862 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003863 struct hci_cp_write_le_host_supported cp;
3864
3865 cp.le = 1;
3866 cp.simul = lmp_le_br_capable(hdev);
3867
3868 /* Check first if we already have the right
3869 * host state (host features set)
3870 */
3871 if (cp.le != lmp_host_le_capable(hdev) ||
3872 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003873 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3874 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003875
3876 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3877 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003878 }
3879
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003880 if (lmp_le_capable(hdev)) {
3881 /* Set random address to static address if configured */
3882 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3883 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3884 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003885
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003886 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3887 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003888 }
3889
Johan Hedberg70da6242013-03-15 17:06:51 -05003890 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3891 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003892 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3893 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003894
3895 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003896 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3897 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003898 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003899 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003900 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003901 }
3902
Johan Hedberg229ab392013-03-15 17:06:53 -05003903 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003904}
3905
Johan Hedberg744cf192011-11-08 20:40:14 +02003906int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003907{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003908 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003909 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3910 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003911 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003912
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003913 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3914 return 0;
3915
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003916 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003917 if (powered_update_hci(hdev) == 0)
3918 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003919
Johan Hedberg229ab392013-03-15 17:06:53 -05003920 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3921 &match);
3922 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003923 }
3924
Johan Hedberg229ab392013-03-15 17:06:53 -05003925 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3926 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3927
3928 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3929 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3930 zero_cod, sizeof(zero_cod), NULL);
3931
3932new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003933 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003934
3935 if (match.sk)
3936 sock_put(match.sk);
3937
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003938 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003939}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003940
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003941void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03003942{
3943 struct pending_cmd *cmd;
3944 u8 status;
3945
3946 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3947 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003948 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03003949
3950 if (err == -ERFKILL)
3951 status = MGMT_STATUS_RFKILLED;
3952 else
3953 status = MGMT_STATUS_FAILED;
3954
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003955 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03003956
3957 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03003958}
3959
Johan Hedberg744cf192011-11-08 20:40:14 +02003960int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003961{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003962 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003963 bool changed = false;
3964 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003965
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003966 if (discoverable) {
3967 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3968 changed = true;
3969 } else {
3970 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3971 changed = true;
3972 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003973
Johan Hedberged9b5f22012-02-21 20:47:06 +02003974 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003975 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003976
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003977 if (changed)
3978 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003979
Johan Hedberg73f22f62010-12-29 16:00:25 +02003980 if (match.sk)
3981 sock_put(match.sk);
3982
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003983 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003984}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003985
Johan Hedberg744cf192011-11-08 20:40:14 +02003986int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003987{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003988 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003989 bool changed = false;
3990 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003991
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003992 if (connectable) {
3993 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3994 changed = true;
3995 } else {
3996 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3997 changed = true;
3998 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003999
Johan Hedberg2b76f452013-03-15 17:07:04 -05004000 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004001
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004002 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004003 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004004
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004005 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004006}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004007
Johan Hedberg744cf192011-11-08 20:40:14 +02004008int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004009{
Johan Hedbergca69b792011-11-11 18:10:00 +02004010 u8 mgmt_err = mgmt_status(status);
4011
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004012 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004013 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004014 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004015
4016 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004017 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004018 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004019
4020 return 0;
4021}
4022
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004023int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4024 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004025{
Johan Hedberg86742e12011-11-07 23:13:38 +02004026 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004027
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004028 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004029
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004030 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004031 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004032 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004033 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004034 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004035 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004036
Johan Hedberg744cf192011-11-08 20:40:14 +02004037 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004038}
Johan Hedbergf7520542011-01-20 12:34:39 +02004039
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004040int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4041{
4042 struct mgmt_ev_new_long_term_key ev;
4043
4044 memset(&ev, 0, sizeof(ev));
4045
4046 ev.store_hint = persistent;
4047 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004048 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004049 ev.key.authenticated = key->authenticated;
4050 ev.key.enc_size = key->enc_size;
4051 ev.key.ediv = key->ediv;
4052
4053 if (key->type == HCI_SMP_LTK)
4054 ev.key.master = 1;
4055
4056 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4057 memcpy(ev.key.val, key->val, sizeof(key->val));
4058
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004059 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4060 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004061}
4062
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004063void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4064 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4065 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004066{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004067 char buf[512];
4068 struct mgmt_ev_device_connected *ev = (void *) buf;
4069 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004070
Johan Hedbergb644ba32012-01-17 21:48:47 +02004071 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004072 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004073
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004074 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004075
Johan Hedbergb644ba32012-01-17 21:48:47 +02004076 if (name_len > 0)
4077 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004078 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004079
4080 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004081 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004082 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004083
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004084 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004085
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004086 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4087 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004088}
4089
Johan Hedberg8962ee72011-01-20 12:40:27 +02004090static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4091{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004092 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004093 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004094 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004095
Johan Hedberg88c3df12012-02-09 14:27:38 +02004096 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4097 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004098
Johan Hedbergaee9b212012-02-18 15:07:59 +02004099 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004100 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004101
4102 *sk = cmd->sk;
4103 sock_hold(*sk);
4104
Johan Hedberga664b5b2011-02-19 12:06:02 -03004105 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004106}
4107
Johan Hedberg124f6e32012-02-09 13:50:12 +02004108static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004109{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004110 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004111 struct mgmt_cp_unpair_device *cp = cmd->param;
4112 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004113
4114 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004115 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4116 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004117
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004118 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4119
Johan Hedbergaee9b212012-02-18 15:07:59 +02004120 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004121
4122 mgmt_pending_remove(cmd);
4123}
4124
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004125void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4126 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004127{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004128 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004129 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004130
Johan Hedberg744cf192011-11-08 20:40:14 +02004131 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004132
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004133 bacpy(&ev.addr.bdaddr, bdaddr);
4134 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4135 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004136
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004137 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004138
4139 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004140 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004141
Johan Hedberg124f6e32012-02-09 13:50:12 +02004142 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004143 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004144}
4145
Marcel Holtmann78929242013-10-06 23:55:47 -07004146void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4147 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004148{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004149 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004150 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004151
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004152 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4153 hdev);
4154
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004155 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004156 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004157 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004158
Johan Hedberg88c3df12012-02-09 14:27:38 +02004159 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004160 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004161
Marcel Holtmann78929242013-10-06 23:55:47 -07004162 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4163 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004164
Johan Hedberga664b5b2011-02-19 12:06:02 -03004165 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004166}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004167
Marcel Holtmann445608d2013-10-06 23:55:48 -07004168void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4169 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004170{
4171 struct mgmt_ev_connect_failed ev;
4172
Johan Hedberg4c659c32011-11-07 23:13:39 +02004173 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004174 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004175 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004176
Marcel Holtmann445608d2013-10-06 23:55:48 -07004177 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004178}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004179
Johan Hedberg744cf192011-11-08 20:40:14 +02004180int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004181{
4182 struct mgmt_ev_pin_code_request ev;
4183
Johan Hedbergd8457692012-02-17 14:24:57 +02004184 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004185 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004186 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004187
Johan Hedberg744cf192011-11-08 20:40:14 +02004188 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004189 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004190}
4191
Johan Hedberg744cf192011-11-08 20:40:14 +02004192int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004193 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004194{
4195 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004196 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004197 int err;
4198
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004199 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004200 if (!cmd)
4201 return -ENOENT;
4202
Johan Hedbergd8457692012-02-17 14:24:57 +02004203 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004204 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004205
Johan Hedbergaee9b212012-02-18 15:07:59 +02004206 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004207 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004208
Johan Hedberga664b5b2011-02-19 12:06:02 -03004209 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004210
4211 return err;
4212}
4213
Johan Hedberg744cf192011-11-08 20:40:14 +02004214int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004215 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004216{
4217 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004218 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004219 int err;
4220
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004221 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004222 if (!cmd)
4223 return -ENOENT;
4224
Johan Hedbergd8457692012-02-17 14:24:57 +02004225 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004226 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004227
Johan Hedbergaee9b212012-02-18 15:07:59 +02004228 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004229 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004230
Johan Hedberga664b5b2011-02-19 12:06:02 -03004231 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004232
4233 return err;
4234}
Johan Hedberga5c29682011-02-19 12:05:57 -03004235
Johan Hedberg744cf192011-11-08 20:40:14 +02004236int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004237 u8 link_type, u8 addr_type, __le32 value,
4238 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004239{
4240 struct mgmt_ev_user_confirm_request ev;
4241
Johan Hedberg744cf192011-11-08 20:40:14 +02004242 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004243
Johan Hedberg272d90d2012-02-09 15:26:12 +02004244 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004245 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004246 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004247 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004248
Johan Hedberg744cf192011-11-08 20:40:14 +02004249 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004250 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004251}
4252
Johan Hedberg272d90d2012-02-09 15:26:12 +02004253int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004254 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004255{
4256 struct mgmt_ev_user_passkey_request ev;
4257
4258 BT_DBG("%s", hdev->name);
4259
Johan Hedberg272d90d2012-02-09 15:26:12 +02004260 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004261 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004262
4263 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004264 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004265}
4266
Brian Gix0df4c182011-11-16 13:53:13 -08004267static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004268 u8 link_type, u8 addr_type, u8 status,
4269 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004270{
4271 struct pending_cmd *cmd;
4272 struct mgmt_rp_user_confirm_reply rp;
4273 int err;
4274
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004275 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004276 if (!cmd)
4277 return -ENOENT;
4278
Johan Hedberg272d90d2012-02-09 15:26:12 +02004279 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004280 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004281 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004282 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004283
Johan Hedberga664b5b2011-02-19 12:06:02 -03004284 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004285
4286 return err;
4287}
4288
Johan Hedberg744cf192011-11-08 20:40:14 +02004289int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004290 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004291{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004292 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004293 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004294}
4295
Johan Hedberg272d90d2012-02-09 15:26:12 +02004296int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004297 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004298{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004299 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004300 status,
4301 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004302}
Johan Hedberg2a611692011-02-19 12:06:00 -03004303
Brian Gix604086b2011-11-23 08:28:33 -08004304int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004305 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004306{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004307 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004308 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004309}
4310
Johan Hedberg272d90d2012-02-09 15:26:12 +02004311int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004312 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004313{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004314 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004315 status,
4316 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004317}
4318
Johan Hedberg92a25252012-09-06 18:39:26 +03004319int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4320 u8 link_type, u8 addr_type, u32 passkey,
4321 u8 entered)
4322{
4323 struct mgmt_ev_passkey_notify ev;
4324
4325 BT_DBG("%s", hdev->name);
4326
4327 bacpy(&ev.addr.bdaddr, bdaddr);
4328 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4329 ev.passkey = __cpu_to_le32(passkey);
4330 ev.entered = entered;
4331
4332 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4333}
4334
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004335int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004336 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004337{
4338 struct mgmt_ev_auth_failed ev;
4339
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004340 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004341 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004342 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004343
Johan Hedberg744cf192011-11-08 20:40:14 +02004344 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004345}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004346
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004347int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4348{
4349 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004350 bool changed = false;
4351 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004352
4353 if (status) {
4354 u8 mgmt_err = mgmt_status(status);
4355 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004356 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004357 return 0;
4358 }
4359
Johan Hedberg47990ea2012-02-22 11:58:37 +02004360 if (test_bit(HCI_AUTH, &hdev->flags)) {
4361 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4362 changed = true;
4363 } else {
4364 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4365 changed = true;
4366 }
4367
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004368 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004369 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004370
Johan Hedberg47990ea2012-02-22 11:58:37 +02004371 if (changed)
4372 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004373
4374 if (match.sk)
4375 sock_put(match.sk);
4376
4377 return err;
4378}
4379
Johan Hedberg890ea892013-03-15 17:06:52 -05004380static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004381{
Johan Hedberg890ea892013-03-15 17:06:52 -05004382 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004383 struct hci_cp_write_eir cp;
4384
Johan Hedberg976eb202012-10-24 21:12:01 +03004385 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004386 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004387
Johan Hedbergc80da272012-02-22 15:38:48 +02004388 memset(hdev->eir, 0, sizeof(hdev->eir));
4389
Johan Hedbergcacaf522012-02-21 00:52:42 +02004390 memset(&cp, 0, sizeof(cp));
4391
Johan Hedberg890ea892013-03-15 17:06:52 -05004392 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004393}
4394
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004395int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004396{
4397 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004398 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004399 bool changed = false;
4400 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004401
4402 if (status) {
4403 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004404
4405 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004406 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004407 err = new_settings(hdev, NULL);
4408
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004409 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4410 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004411
4412 return err;
4413 }
4414
4415 if (enable) {
4416 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4417 changed = true;
4418 } else {
4419 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4420 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004421 }
4422
4423 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4424
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004425 if (changed)
4426 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004427
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004428 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004429 sock_put(match.sk);
4430
Johan Hedberg890ea892013-03-15 17:06:52 -05004431 hci_req_init(&req, hdev);
4432
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004433 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004434 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004435 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004436 clear_eir(&req);
4437
4438 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004439
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004440 return err;
4441}
4442
Johan Hedberg92da6092013-03-15 17:06:55 -05004443static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004444{
4445 struct cmd_lookup *match = data;
4446
Johan Hedberg90e70452012-02-23 23:09:40 +02004447 if (match->sk == NULL) {
4448 match->sk = cmd->sk;
4449 sock_hold(match->sk);
4450 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004451}
4452
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004453int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004454 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004455{
Johan Hedberg90e70452012-02-23 23:09:40 +02004456 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4457 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004458
Johan Hedberg92da6092013-03-15 17:06:55 -05004459 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4460 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4461 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004462
4463 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004464 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4465 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004466
4467 if (match.sk)
4468 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004469
4470 return err;
4471}
4472
Johan Hedberg744cf192011-11-08 20:40:14 +02004473int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004474{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004475 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004476 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004477
Johan Hedberg13928972013-03-15 17:07:00 -05004478 if (status)
4479 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004480
4481 memset(&ev, 0, sizeof(ev));
4482 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004483 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004484
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004485 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004486 if (!cmd) {
4487 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004488
Johan Hedberg13928972013-03-15 17:07:00 -05004489 /* If this is a HCI command related to powering on the
4490 * HCI dev don't send any mgmt signals.
4491 */
4492 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4493 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004494 }
4495
Johan Hedberg13928972013-03-15 17:07:00 -05004496 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4497 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004498}
Szymon Jancc35938b2011-03-22 13:12:21 +01004499
Johan Hedberg744cf192011-11-08 20:40:14 +02004500int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004501 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004502{
4503 struct pending_cmd *cmd;
4504 int err;
4505
Johan Hedberg744cf192011-11-08 20:40:14 +02004506 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004507
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004508 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004509 if (!cmd)
4510 return -ENOENT;
4511
4512 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004513 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4514 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004515 } else {
4516 struct mgmt_rp_read_local_oob_data rp;
4517
4518 memcpy(rp.hash, hash, sizeof(rp.hash));
4519 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4520
Johan Hedberg744cf192011-11-08 20:40:14 +02004521 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004522 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4523 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004524 }
4525
4526 mgmt_pending_remove(cmd);
4527
4528 return err;
4529}
Johan Hedberge17acd42011-03-30 23:57:16 +03004530
Marcel Holtmann901801b2013-10-06 23:55:51 -07004531void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4532 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4533 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004534{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004535 char buf[512];
4536 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004537 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004538
Andre Guedes12602d02013-04-30 15:29:40 -03004539 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004540 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004541
Johan Hedberg1dc06092012-01-15 21:01:23 +02004542 /* Leave 5 bytes for a potential CoD field */
4543 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004544 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004545
Johan Hedberg1dc06092012-01-15 21:01:23 +02004546 memset(buf, 0, sizeof(buf));
4547
Johan Hedberge319d2e2012-01-15 19:51:59 +02004548 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004549 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004550 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004551 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304552 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004553 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304554 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004555
Johan Hedberg1dc06092012-01-15 21:01:23 +02004556 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004557 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004558
Johan Hedberg1dc06092012-01-15 21:01:23 +02004559 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4560 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004561 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004562
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004563 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004564 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004565
Marcel Holtmann901801b2013-10-06 23:55:51 -07004566 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004567}
Johan Hedberga88a9652011-03-30 13:18:12 +03004568
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004569void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4570 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004571{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004572 struct mgmt_ev_device_found *ev;
4573 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4574 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004575
Johan Hedbergb644ba32012-01-17 21:48:47 +02004576 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004577
Johan Hedbergb644ba32012-01-17 21:48:47 +02004578 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004579
Johan Hedbergb644ba32012-01-17 21:48:47 +02004580 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004581 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004582 ev->rssi = rssi;
4583
4584 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004585 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004586
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004587 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004588
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004589 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004590}
Johan Hedberg314b2382011-04-27 10:29:57 -04004591
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004592void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004593{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004594 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004595 struct pending_cmd *cmd;
4596
Andre Guedes343fb142011-11-22 17:14:19 -03004597 BT_DBG("%s discovering %u", hdev->name, discovering);
4598
Johan Hedberg164a6e72011-11-01 17:06:44 +02004599 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004600 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004601 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004602 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004603
4604 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004605 u8 type = hdev->discovery.type;
4606
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004607 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4608 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004609 mgmt_pending_remove(cmd);
4610 }
4611
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004612 memset(&ev, 0, sizeof(ev));
4613 ev.type = hdev->discovery.type;
4614 ev.discovering = discovering;
4615
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004616 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004617}
Antti Julku5e762442011-08-25 16:48:02 +03004618
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004619int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004620{
4621 struct pending_cmd *cmd;
4622 struct mgmt_ev_device_blocked ev;
4623
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004624 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004625
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004626 bacpy(&ev.addr.bdaddr, bdaddr);
4627 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004628
Johan Hedberg744cf192011-11-08 20:40:14 +02004629 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004630 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004631}
4632
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004633int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004634{
4635 struct pending_cmd *cmd;
4636 struct mgmt_ev_device_unblocked ev;
4637
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004638 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004639
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004640 bacpy(&ev.addr.bdaddr, bdaddr);
4641 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004642
Johan Hedberg744cf192011-11-08 20:40:14 +02004643 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004644 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004645}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004646
4647static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4648{
4649 BT_DBG("%s status %u", hdev->name, status);
4650
4651 /* Clear the advertising mgmt setting if we failed to re-enable it */
4652 if (status) {
4653 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004654 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004655 }
4656}
4657
4658void mgmt_reenable_advertising(struct hci_dev *hdev)
4659{
4660 struct hci_request req;
4661
4662 if (hdev->conn_hash.le_num)
4663 return;
4664
4665 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4666 return;
4667
4668 hci_req_init(&req, hdev);
4669 enable_advertising(&req);
4670
4671 /* If this fails we have no option but to let user space know
4672 * that we've disabled advertising.
4673 */
4674 if (hci_req_run(&req, adv_enable_complete) < 0) {
4675 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004676 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004677 }
4678}