blob: 2793bfe48707ab6759b14eb05628f6094b7c712e [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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200201
Andre Guedes790eff42012-06-07 19:05:46 -0300202 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200218 kfree_skb(skb);
219
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300220 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200221}
222
Johan Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200413
Johan Hedberg84bde9d2012-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 Hedbergf7b64e62010-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 Hedberg84bde9d2012-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 Hedbergaee9b2182012-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 Hedbergf7b64e62010-12-13 21:07:06 +0200959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300960 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001313 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001314
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001315 if (cp->val) {
1316 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1317 &hdev->dev_flags);
1318 } else {
1319 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1320 &hdev->dev_flags);
1321 if (!changed)
1322 changed = test_and_clear_bit(HCI_HS_ENABLED,
1323 &hdev->dev_flags);
1324 else
1325 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001326 }
1327
1328 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1329 if (err < 0)
1330 goto failed;
1331
1332 if (changed)
1333 err = new_settings(hdev, sk);
1334
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001335 goto failed;
1336 }
1337
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001338 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1339 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001340 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1341 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001342 goto failed;
1343 }
1344
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001345 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001346 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1347 goto failed;
1348 }
1349
1350 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1351 if (!cmd) {
1352 err = -ENOMEM;
1353 goto failed;
1354 }
1355
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001356 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001357 if (err < 0) {
1358 mgmt_pending_remove(cmd);
1359 goto failed;
1360 }
1361
1362failed:
1363 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001364 return err;
1365}
1366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001367static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001368{
1369 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001370 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001371 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001372 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001374 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001375
Johan Hedberge6fe7982013-10-02 15:45:22 +03001376 status = mgmt_bredr_support(hdev);
1377 if (status)
1378 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001379
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001380 if (!lmp_ssp_capable(hdev))
1381 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1382 MGMT_STATUS_NOT_SUPPORTED);
1383
1384 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1385 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1386 MGMT_STATUS_REJECTED);
1387
Johan Hedberga7e80f22013-01-09 16:05:19 +02001388 if (cp->val != 0x00 && cp->val != 0x01)
1389 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1390 MGMT_STATUS_INVALID_PARAMS);
1391
Marcel Holtmannee392692013-10-01 22:59:23 -07001392 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001393
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001394 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001395 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001396 } else {
1397 if (hdev_is_powered(hdev)) {
1398 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1399 MGMT_STATUS_REJECTED);
1400 goto unlock;
1401 }
1402
Marcel Holtmannee392692013-10-01 22:59:23 -07001403 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001404 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001405
1406 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1407 if (err < 0)
1408 goto unlock;
1409
1410 if (changed)
1411 err = new_settings(hdev, sk);
1412
1413unlock:
1414 hci_dev_unlock(hdev);
1415 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001416}
1417
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001418static void enable_advertising(struct hci_request *req)
1419{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001420 struct hci_dev *hdev = req->hdev;
1421 struct hci_cp_le_set_adv_param cp;
1422 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001423
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001424 memset(&cp, 0, sizeof(cp));
1425 cp.min_interval = __constant_cpu_to_le16(0x0800);
1426 cp.max_interval = __constant_cpu_to_le16(0x0800);
1427 cp.type = LE_ADV_IND;
1428 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1429 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1430 else
1431 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1432 cp.channel_map = 0x07;
1433
1434 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1435
1436 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001437}
1438
1439static void disable_advertising(struct hci_request *req)
1440{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001441 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001442
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001443 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001444}
1445
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001446static void le_enable_complete(struct hci_dev *hdev, u8 status)
1447{
1448 struct cmd_lookup match = { NULL, hdev };
1449
1450 if (status) {
1451 u8 mgmt_err = mgmt_status(status);
1452
1453 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1454 &mgmt_err);
1455 return;
1456 }
1457
1458 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1459
1460 new_settings(hdev, match.sk);
1461
1462 if (match.sk)
1463 sock_put(match.sk);
1464}
1465
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001466static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001467{
1468 struct mgmt_mode *cp = data;
1469 struct hci_cp_write_le_host_supported hci_cp;
1470 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001471 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001472 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001473 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001474
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001475 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001476
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001477 if (!lmp_le_capable(hdev))
1478 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1479 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001480
Johan Hedberga7e80f22013-01-09 16:05:19 +02001481 if (cp->val != 0x00 && cp->val != 0x01)
1482 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1483 MGMT_STATUS_INVALID_PARAMS);
1484
Johan Hedbergc73eee92013-04-19 18:35:21 +03001485 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001486 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001487 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1488 MGMT_STATUS_REJECTED);
1489
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001490 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001491
1492 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001493 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001494
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001495 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001496 bool changed = false;
1497
1498 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1499 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1500 changed = true;
1501 }
1502
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001503 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1504 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001505 changed = true;
1506 }
1507
Johan Hedberg06199cf2012-02-22 16:37:11 +02001508 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1509 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001510 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001511
1512 if (changed)
1513 err = new_settings(hdev, sk);
1514
Johan Hedberg1de028c2012-02-29 19:55:35 -08001515 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001516 }
1517
Johan Hedberg4375f102013-09-25 13:26:10 +03001518 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1519 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001520 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001521 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001522 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001523 }
1524
1525 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1526 if (!cmd) {
1527 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001528 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001529 }
1530
1531 memset(&hci_cp, 0, sizeof(hci_cp));
1532
1533 if (val) {
1534 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001535 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001536 }
1537
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001538 hci_req_init(&req, hdev);
1539
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001540 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1541 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001542
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001543 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1544 &hci_cp);
1545
1546 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301547 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001548 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001549
Johan Hedberg1de028c2012-02-29 19:55:35 -08001550unlock:
1551 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001552 return err;
1553}
1554
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001555/* This is a helper function to test for pending mgmt commands that can
1556 * cause CoD or EIR HCI commands. We can only allow one such pending
1557 * mgmt command at a time since otherwise we cannot easily track what
1558 * the current values are, will be, and based on that calculate if a new
1559 * HCI command needs to be sent and if yes with what value.
1560 */
1561static bool pending_eir_or_class(struct hci_dev *hdev)
1562{
1563 struct pending_cmd *cmd;
1564
1565 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1566 switch (cmd->opcode) {
1567 case MGMT_OP_ADD_UUID:
1568 case MGMT_OP_REMOVE_UUID:
1569 case MGMT_OP_SET_DEV_CLASS:
1570 case MGMT_OP_SET_POWERED:
1571 return true;
1572 }
1573 }
1574
1575 return false;
1576}
1577
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001578static const u8 bluetooth_base_uuid[] = {
1579 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1580 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1581};
1582
1583static u8 get_uuid_size(const u8 *uuid)
1584{
1585 u32 val;
1586
1587 if (memcmp(uuid, bluetooth_base_uuid, 12))
1588 return 128;
1589
1590 val = get_unaligned_le32(&uuid[12]);
1591 if (val > 0xffff)
1592 return 32;
1593
1594 return 16;
1595}
1596
Johan Hedberg92da6092013-03-15 17:06:55 -05001597static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1598{
1599 struct pending_cmd *cmd;
1600
1601 hci_dev_lock(hdev);
1602
1603 cmd = mgmt_pending_find(mgmt_op, hdev);
1604 if (!cmd)
1605 goto unlock;
1606
1607 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1608 hdev->dev_class, 3);
1609
1610 mgmt_pending_remove(cmd);
1611
1612unlock:
1613 hci_dev_unlock(hdev);
1614}
1615
1616static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1617{
1618 BT_DBG("status 0x%02x", status);
1619
1620 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1621}
1622
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001623static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001624{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001625 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001626 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001627 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001628 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001629 int err;
1630
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001631 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001632
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001633 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001634
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001635 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001636 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001637 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001638 goto failed;
1639 }
1640
Andre Guedes92c4c202012-06-07 19:05:44 -03001641 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001642 if (!uuid) {
1643 err = -ENOMEM;
1644 goto failed;
1645 }
1646
1647 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001648 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001649 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001650
Johan Hedbergde66aa62013-01-27 00:31:27 +02001651 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001652
Johan Hedberg890ea892013-03-15 17:06:52 -05001653 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001654
Johan Hedberg890ea892013-03-15 17:06:52 -05001655 update_class(&req);
1656 update_eir(&req);
1657
Johan Hedberg92da6092013-03-15 17:06:55 -05001658 err = hci_req_run(&req, add_uuid_complete);
1659 if (err < 0) {
1660 if (err != -ENODATA)
1661 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001663 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001664 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001665 goto failed;
1666 }
1667
1668 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001669 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001670 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001671 goto failed;
1672 }
1673
1674 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001675
1676failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001677 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001678 return err;
1679}
1680
Johan Hedberg24b78d02012-02-23 23:24:30 +02001681static bool enable_service_cache(struct hci_dev *hdev)
1682{
1683 if (!hdev_is_powered(hdev))
1684 return false;
1685
1686 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001687 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1688 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001689 return true;
1690 }
1691
1692 return false;
1693}
1694
Johan Hedberg92da6092013-03-15 17:06:55 -05001695static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1696{
1697 BT_DBG("status 0x%02x", status);
1698
1699 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1700}
1701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001702static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001703 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001704{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001705 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001706 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001707 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001708 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 -05001709 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001710 int err, found;
1711
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001712 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001713
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001714 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001715
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001716 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001717 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001718 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001719 goto unlock;
1720 }
1721
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001722 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1723 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001724
Johan Hedberg24b78d02012-02-23 23:24:30 +02001725 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001726 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001727 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001728 goto unlock;
1729 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001730
Johan Hedberg9246a862012-02-23 21:33:16 +02001731 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001732 }
1733
1734 found = 0;
1735
Johan Hedberg056341c2013-01-27 00:31:30 +02001736 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001737 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1738 continue;
1739
1740 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001741 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001742 found++;
1743 }
1744
1745 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001746 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001747 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001748 goto unlock;
1749 }
1750
Johan Hedberg9246a862012-02-23 21:33:16 +02001751update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001752 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001753
Johan Hedberg890ea892013-03-15 17:06:52 -05001754 update_class(&req);
1755 update_eir(&req);
1756
Johan Hedberg92da6092013-03-15 17:06:55 -05001757 err = hci_req_run(&req, remove_uuid_complete);
1758 if (err < 0) {
1759 if (err != -ENODATA)
1760 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001761
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001762 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001763 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001764 goto unlock;
1765 }
1766
1767 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001768 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001769 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001770 goto unlock;
1771 }
1772
1773 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001774
1775unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001776 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001777 return err;
1778}
1779
Johan Hedberg92da6092013-03-15 17:06:55 -05001780static void set_class_complete(struct hci_dev *hdev, u8 status)
1781{
1782 BT_DBG("status 0x%02x", status);
1783
1784 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1785}
1786
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001787static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001788 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001789{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001790 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001791 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001792 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001793 int err;
1794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001795 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001796
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001797 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001798 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1799 MGMT_STATUS_NOT_SUPPORTED);
1800
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001801 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001802
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001803 if (pending_eir_or_class(hdev)) {
1804 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1805 MGMT_STATUS_BUSY);
1806 goto unlock;
1807 }
1808
1809 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1810 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1811 MGMT_STATUS_INVALID_PARAMS);
1812 goto unlock;
1813 }
1814
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001815 hdev->major_class = cp->major;
1816 hdev->minor_class = cp->minor;
1817
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001818 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001819 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001820 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001821 goto unlock;
1822 }
1823
Johan Hedberg890ea892013-03-15 17:06:52 -05001824 hci_req_init(&req, hdev);
1825
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001826 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001827 hci_dev_unlock(hdev);
1828 cancel_delayed_work_sync(&hdev->service_cache);
1829 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001830 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001831 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001832
Johan Hedberg890ea892013-03-15 17:06:52 -05001833 update_class(&req);
1834
Johan Hedberg92da6092013-03-15 17:06:55 -05001835 err = hci_req_run(&req, set_class_complete);
1836 if (err < 0) {
1837 if (err != -ENODATA)
1838 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001839
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001840 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001841 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001842 goto unlock;
1843 }
1844
1845 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001846 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001847 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001848 goto unlock;
1849 }
1850
1851 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001852
Johan Hedbergb5235a62012-02-21 14:32:24 +02001853unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001854 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001855 return err;
1856}
1857
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001858static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001859 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001860{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001861 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001862 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001863 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001864
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001865 BT_DBG("request for %s", hdev->name);
1866
1867 if (!lmp_bredr_capable(hdev))
1868 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1869 MGMT_STATUS_NOT_SUPPORTED);
1870
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001871 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001872
Johan Hedberg86742e12011-11-07 23:13:38 +02001873 expected_len = sizeof(*cp) + key_count *
1874 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001875 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001876 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001877 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001878 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001879 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001880 }
1881
Johan Hedberg4ae14302013-01-20 14:27:13 +02001882 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1883 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1884 MGMT_STATUS_INVALID_PARAMS);
1885
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001886 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001887 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001888
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001889 for (i = 0; i < key_count; i++) {
1890 struct mgmt_link_key_info *key = &cp->keys[i];
1891
1892 if (key->addr.type != BDADDR_BREDR)
1893 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1894 MGMT_STATUS_INVALID_PARAMS);
1895 }
1896
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001897 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001898
1899 hci_link_keys_clear(hdev);
1900
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001901 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001902 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001903 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001904 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001905
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001906 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001907 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001908
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001909 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001910 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001911 }
1912
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001913 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001914
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001915 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001916
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001917 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001918}
1919
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001920static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001921 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001922{
1923 struct mgmt_ev_device_unpaired ev;
1924
1925 bacpy(&ev.addr.bdaddr, bdaddr);
1926 ev.addr.type = addr_type;
1927
1928 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001929 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001930}
1931
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001932static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001933 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001934{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001935 struct mgmt_cp_unpair_device *cp = data;
1936 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001937 struct hci_cp_disconnect dc;
1938 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001939 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001940 int err;
1941
Johan Hedberga8a1d192011-11-10 15:54:38 +02001942 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001943 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1944 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001945
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001946 if (!bdaddr_type_is_valid(cp->addr.type))
1947 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1948 MGMT_STATUS_INVALID_PARAMS,
1949 &rp, sizeof(rp));
1950
Johan Hedberg118da702013-01-20 14:27:20 +02001951 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1952 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1953 MGMT_STATUS_INVALID_PARAMS,
1954 &rp, sizeof(rp));
1955
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001956 hci_dev_lock(hdev);
1957
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001958 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001959 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001960 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001961 goto unlock;
1962 }
1963
Andre Guedes591f47f2012-04-24 21:02:49 -03001964 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001965 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1966 else
1967 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001968
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001969 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001970 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001971 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001972 goto unlock;
1973 }
1974
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001975 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001976 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001977 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001978 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001979 else
1980 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001981 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001982 } else {
1983 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001984 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001985
Johan Hedberga8a1d192011-11-10 15:54:38 +02001986 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001987 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001988 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001989 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001990 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001991 }
1992
Johan Hedberg124f6e32012-02-09 13:50:12 +02001993 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001994 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001995 if (!cmd) {
1996 err = -ENOMEM;
1997 goto unlock;
1998 }
1999
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002000 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002001 dc.reason = 0x13; /* Remote User Terminated Connection */
2002 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2003 if (err < 0)
2004 mgmt_pending_remove(cmd);
2005
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002006unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002007 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002008 return err;
2009}
2010
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002011static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002012 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002013{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002014 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002015 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002016 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002017 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002018 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002019 int err;
2020
2021 BT_DBG("");
2022
Johan Hedberg06a63b12013-01-20 14:27:21 +02002023 memset(&rp, 0, sizeof(rp));
2024 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2025 rp.addr.type = cp->addr.type;
2026
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002027 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002028 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2029 MGMT_STATUS_INVALID_PARAMS,
2030 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002031
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002032 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002033
2034 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002035 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2036 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002037 goto failed;
2038 }
2039
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002040 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002041 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2042 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002043 goto failed;
2044 }
2045
Andre Guedes591f47f2012-04-24 21:02:49 -03002046 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002047 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2048 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002049 else
2050 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002051
Vishal Agarwalf9607272012-06-13 05:32:43 +05302052 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002053 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2054 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002055 goto failed;
2056 }
2057
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002058 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002059 if (!cmd) {
2060 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002061 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002062 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002063
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002064 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002065 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002066
2067 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2068 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002069 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002070
2071failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002072 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002073 return err;
2074}
2075
Andre Guedes57c14772012-04-24 21:02:50 -03002076static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002077{
2078 switch (link_type) {
2079 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002080 switch (addr_type) {
2081 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002082 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002083
Johan Hedberg48264f02011-11-09 13:58:58 +02002084 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002085 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002086 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002087 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002088
Johan Hedberg4c659c32011-11-07 23:13:39 +02002089 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002090 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002091 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002092 }
2093}
2094
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002095static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2096 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002097{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002098 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002099 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002100 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002101 int err;
2102 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002103
2104 BT_DBG("");
2105
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002106 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002107
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002108 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002110 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002111 goto unlock;
2112 }
2113
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002114 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002115 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2116 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002117 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002118 }
2119
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002120 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002121 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002122 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002123 err = -ENOMEM;
2124 goto unlock;
2125 }
2126
Johan Hedberg2784eb42011-01-21 13:56:35 +02002127 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002128 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002129 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2130 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002131 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002132 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002133 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002134 continue;
2135 i++;
2136 }
2137
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002138 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002139
Johan Hedberg4c659c32011-11-07 23:13:39 +02002140 /* Recalculate length in case of filtered SCO connections, etc */
2141 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002142
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002143 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002144 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002145
Johan Hedberga38528f2011-01-22 06:46:43 +02002146 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002147
2148unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002149 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002150 return err;
2151}
2152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002153static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002154 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002155{
2156 struct pending_cmd *cmd;
2157 int err;
2158
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002159 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002160 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002161 if (!cmd)
2162 return -ENOMEM;
2163
Johan Hedbergd8457692012-02-17 14:24:57 +02002164 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002165 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002166 if (err < 0)
2167 mgmt_pending_remove(cmd);
2168
2169 return err;
2170}
2171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002172static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002173 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002174{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002175 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002176 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002177 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002178 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179 int err;
2180
2181 BT_DBG("");
2182
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002183 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002184
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002185 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002186 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002187 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002188 goto failed;
2189 }
2190
Johan Hedbergd8457692012-02-17 14:24:57 +02002191 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002192 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002194 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002195 goto failed;
2196 }
2197
2198 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002199 struct mgmt_cp_pin_code_neg_reply ncp;
2200
2201 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002202
2203 BT_ERR("PIN code is not 16 bytes long");
2204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002205 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002206 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002207 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002208 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002209
2210 goto failed;
2211 }
2212
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002213 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002214 if (!cmd) {
2215 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002216 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002217 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002218
Johan Hedbergd8457692012-02-17 14:24:57 +02002219 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002220 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002221 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002222
2223 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2224 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002225 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002226
2227failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002228 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002229 return err;
2230}
2231
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002232static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2233 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002234{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002235 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002236
2237 BT_DBG("");
2238
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002239 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002240
2241 hdev->io_capability = cp->io_capability;
2242
2243 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002244 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002245
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002246 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002247
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002248 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2249 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002250}
2251
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002252static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002253{
2254 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002255 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002256
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002257 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002258 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2259 continue;
2260
Johan Hedberge9a416b2011-02-19 12:05:56 -03002261 if (cmd->user_data != conn)
2262 continue;
2263
2264 return cmd;
2265 }
2266
2267 return NULL;
2268}
2269
2270static void pairing_complete(struct pending_cmd *cmd, u8 status)
2271{
2272 struct mgmt_rp_pair_device rp;
2273 struct hci_conn *conn = cmd->user_data;
2274
Johan Hedbergba4e5642011-11-11 00:07:34 +02002275 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002276 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002277
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002278 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002279 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002280
2281 /* So we don't get further callbacks for this connection */
2282 conn->connect_cfm_cb = NULL;
2283 conn->security_cfm_cb = NULL;
2284 conn->disconn_cfm_cb = NULL;
2285
David Herrmann76a68ba2013-04-06 20:28:37 +02002286 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002287
Johan Hedberga664b5b2011-02-19 12:06:02 -03002288 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002289}
2290
2291static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2292{
2293 struct pending_cmd *cmd;
2294
2295 BT_DBG("status %u", status);
2296
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002297 cmd = find_pairing(conn);
2298 if (!cmd)
2299 BT_DBG("Unable to find a pending command");
2300 else
Johan Hedberge2113262012-02-18 15:20:03 +02002301 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002302}
2303
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302304static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2305{
2306 struct pending_cmd *cmd;
2307
2308 BT_DBG("status %u", status);
2309
2310 if (!status)
2311 return;
2312
2313 cmd = find_pairing(conn);
2314 if (!cmd)
2315 BT_DBG("Unable to find a pending command");
2316 else
2317 pairing_complete(cmd, mgmt_status(status));
2318}
2319
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002320static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002321 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002322{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002323 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002324 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002325 struct pending_cmd *cmd;
2326 u8 sec_level, auth_type;
2327 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002328 int err;
2329
2330 BT_DBG("");
2331
Szymon Jancf950a30e2013-01-18 12:48:07 +01002332 memset(&rp, 0, sizeof(rp));
2333 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2334 rp.addr.type = cp->addr.type;
2335
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002336 if (!bdaddr_type_is_valid(cp->addr.type))
2337 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2338 MGMT_STATUS_INVALID_PARAMS,
2339 &rp, sizeof(rp));
2340
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002341 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002342
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002343 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002344 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2345 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002346 goto unlock;
2347 }
2348
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002349 sec_level = BT_SECURITY_MEDIUM;
2350 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002351 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002352 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002353 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002354
Andre Guedes591f47f2012-04-24 21:02:49 -03002355 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002356 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2357 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002358 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002359 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2360 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002361
Ville Tervo30e76272011-02-22 16:10:53 -03002362 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002363 int status;
2364
2365 if (PTR_ERR(conn) == -EBUSY)
2366 status = MGMT_STATUS_BUSY;
2367 else
2368 status = MGMT_STATUS_CONNECT_FAILED;
2369
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002370 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002371 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002372 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002373 goto unlock;
2374 }
2375
2376 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002377 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002378 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002379 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002380 goto unlock;
2381 }
2382
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002383 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002384 if (!cmd) {
2385 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002386 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002387 goto unlock;
2388 }
2389
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002390 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002391 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002392 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302393 else
2394 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002395
Johan Hedberge9a416b2011-02-19 12:05:56 -03002396 conn->security_cfm_cb = pairing_complete_cb;
2397 conn->disconn_cfm_cb = pairing_complete_cb;
2398 conn->io_capability = cp->io_cap;
2399 cmd->user_data = conn;
2400
2401 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002402 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002403 pairing_complete(cmd, 0);
2404
2405 err = 0;
2406
2407unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002408 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002409 return err;
2410}
2411
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002412static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2413 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002414{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002415 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002416 struct pending_cmd *cmd;
2417 struct hci_conn *conn;
2418 int err;
2419
2420 BT_DBG("");
2421
Johan Hedberg28424702012-02-02 04:02:29 +02002422 hci_dev_lock(hdev);
2423
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002424 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002425 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002426 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002427 goto unlock;
2428 }
2429
Johan Hedberg28424702012-02-02 04:02:29 +02002430 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2431 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002432 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002433 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002434 goto unlock;
2435 }
2436
2437 conn = cmd->user_data;
2438
2439 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002440 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002441 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002442 goto unlock;
2443 }
2444
2445 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2446
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002447 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002448 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002449unlock:
2450 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002451 return err;
2452}
2453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002455 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002456 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002457{
Johan Hedberga5c29682011-02-19 12:05:57 -03002458 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002459 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002460 int err;
2461
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002462 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002463
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002464 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002465 err = cmd_complete(sk, hdev->id, mgmt_op,
2466 MGMT_STATUS_NOT_POWERED, addr,
2467 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002468 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002469 }
2470
Johan Hedberg1707c602013-03-15 17:07:15 -05002471 if (addr->type == BDADDR_BREDR)
2472 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002473 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002474 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002475
Johan Hedberg272d90d2012-02-09 15:26:12 +02002476 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002477 err = cmd_complete(sk, hdev->id, mgmt_op,
2478 MGMT_STATUS_NOT_CONNECTED, addr,
2479 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002480 goto done;
2481 }
2482
Johan Hedberg1707c602013-03-15 17:07:15 -05002483 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002484 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002485 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002486
Brian Gix5fe57d92011-12-21 16:12:13 -08002487 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002488 err = cmd_complete(sk, hdev->id, mgmt_op,
2489 MGMT_STATUS_SUCCESS, addr,
2490 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002491 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002492 err = cmd_complete(sk, hdev->id, mgmt_op,
2493 MGMT_STATUS_FAILED, addr,
2494 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002495
Brian Gix47c15e22011-11-16 13:53:14 -08002496 goto done;
2497 }
2498
Johan Hedberg1707c602013-03-15 17:07:15 -05002499 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002500 if (!cmd) {
2501 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002502 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002503 }
2504
Brian Gix0df4c182011-11-16 13:53:13 -08002505 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002506 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2507 struct hci_cp_user_passkey_reply cp;
2508
Johan Hedberg1707c602013-03-15 17:07:15 -05002509 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002510 cp.passkey = passkey;
2511 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2512 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002513 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2514 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002515
Johan Hedberga664b5b2011-02-19 12:06:02 -03002516 if (err < 0)
2517 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002518
Brian Gix0df4c182011-11-16 13:53:13 -08002519done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002520 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002521 return err;
2522}
2523
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302524static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2525 void *data, u16 len)
2526{
2527 struct mgmt_cp_pin_code_neg_reply *cp = data;
2528
2529 BT_DBG("");
2530
Johan Hedberg1707c602013-03-15 17:07:15 -05002531 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302532 MGMT_OP_PIN_CODE_NEG_REPLY,
2533 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2534}
2535
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2537 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002538{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002539 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002540
2541 BT_DBG("");
2542
2543 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002544 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002545 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002546
Johan Hedberg1707c602013-03-15 17:07:15 -05002547 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002548 MGMT_OP_USER_CONFIRM_REPLY,
2549 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002550}
2551
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002552static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002553 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002554{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002555 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002556
2557 BT_DBG("");
2558
Johan Hedberg1707c602013-03-15 17:07:15 -05002559 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002560 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2561 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002562}
2563
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002564static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2565 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002566{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002567 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002568
2569 BT_DBG("");
2570
Johan Hedberg1707c602013-03-15 17:07:15 -05002571 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002572 MGMT_OP_USER_PASSKEY_REPLY,
2573 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002574}
2575
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002576static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002577 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002578{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002579 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002580
2581 BT_DBG("");
2582
Johan Hedberg1707c602013-03-15 17:07:15 -05002583 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002584 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2585 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002586}
2587
Johan Hedberg13928972013-03-15 17:07:00 -05002588static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002589{
Johan Hedberg13928972013-03-15 17:07:00 -05002590 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002591 struct hci_cp_write_local_name cp;
2592
Johan Hedberg13928972013-03-15 17:07:00 -05002593 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002594
Johan Hedberg890ea892013-03-15 17:06:52 -05002595 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002596}
2597
Johan Hedberg13928972013-03-15 17:07:00 -05002598static void set_name_complete(struct hci_dev *hdev, u8 status)
2599{
2600 struct mgmt_cp_set_local_name *cp;
2601 struct pending_cmd *cmd;
2602
2603 BT_DBG("status 0x%02x", status);
2604
2605 hci_dev_lock(hdev);
2606
2607 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2608 if (!cmd)
2609 goto unlock;
2610
2611 cp = cmd->param;
2612
2613 if (status)
2614 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2615 mgmt_status(status));
2616 else
2617 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2618 cp, sizeof(*cp));
2619
2620 mgmt_pending_remove(cmd);
2621
2622unlock:
2623 hci_dev_unlock(hdev);
2624}
2625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002627 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002628{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002629 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002630 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002631 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002632 int err;
2633
2634 BT_DBG("");
2635
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002636 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002637
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002638 /* If the old values are the same as the new ones just return a
2639 * direct command complete event.
2640 */
2641 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2642 !memcmp(hdev->short_name, cp->short_name,
2643 sizeof(hdev->short_name))) {
2644 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2645 data, len);
2646 goto failed;
2647 }
2648
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002649 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002650
Johan Hedbergb5235a62012-02-21 14:32:24 +02002651 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002652 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002653
2654 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002655 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002656 if (err < 0)
2657 goto failed;
2658
2659 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002660 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002661
Johan Hedbergb5235a62012-02-21 14:32:24 +02002662 goto failed;
2663 }
2664
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002665 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002666 if (!cmd) {
2667 err = -ENOMEM;
2668 goto failed;
2669 }
2670
Johan Hedberg13928972013-03-15 17:07:00 -05002671 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2672
Johan Hedberg890ea892013-03-15 17:06:52 -05002673 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002674
2675 if (lmp_bredr_capable(hdev)) {
2676 update_name(&req);
2677 update_eir(&req);
2678 }
2679
2680 if (lmp_le_capable(hdev))
2681 hci_update_ad(&req);
2682
Johan Hedberg13928972013-03-15 17:07:00 -05002683 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002684 if (err < 0)
2685 mgmt_pending_remove(cmd);
2686
2687failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002688 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002689 return err;
2690}
2691
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002692static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002693 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002694{
Szymon Jancc35938b2011-03-22 13:12:21 +01002695 struct pending_cmd *cmd;
2696 int err;
2697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002699
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002700 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002701
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002702 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002703 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002704 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002705 goto unlock;
2706 }
2707
Andre Guedes9a1a1992012-07-24 15:03:48 -03002708 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002709 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002710 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002711 goto unlock;
2712 }
2713
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002714 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002715 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002716 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002717 goto unlock;
2718 }
2719
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002720 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002721 if (!cmd) {
2722 err = -ENOMEM;
2723 goto unlock;
2724 }
2725
2726 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2727 if (err < 0)
2728 mgmt_pending_remove(cmd);
2729
2730unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002731 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002732 return err;
2733}
2734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002735static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002736 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002737{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002738 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002739 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002740 int err;
2741
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002742 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002743
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002744 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002745
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002746 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002748 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002749 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002750 else
Szymon Janca6785be2012-12-13 15:11:21 +01002751 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002752
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002753 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002755
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002756 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002757 return err;
2758}
2759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002761 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002762{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002763 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002764 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002765 int err;
2766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002767 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002768
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002769 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002770
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002771 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002772 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002773 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002774 else
Szymon Janca6785be2012-12-13 15:11:21 +01002775 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002776
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002777 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002778 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002779
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002780 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002781 return err;
2782}
2783
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002784static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2785{
2786 struct pending_cmd *cmd;
2787 u8 type;
2788 int err;
2789
2790 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2791
2792 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2793 if (!cmd)
2794 return -ENOENT;
2795
2796 type = hdev->discovery.type;
2797
2798 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2799 &type, sizeof(type));
2800 mgmt_pending_remove(cmd);
2801
2802 return err;
2803}
2804
Andre Guedes7c307722013-04-30 15:29:28 -03002805static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2806{
2807 BT_DBG("status %d", status);
2808
2809 if (status) {
2810 hci_dev_lock(hdev);
2811 mgmt_start_discovery_failed(hdev, status);
2812 hci_dev_unlock(hdev);
2813 return;
2814 }
2815
2816 hci_dev_lock(hdev);
2817 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2818 hci_dev_unlock(hdev);
2819
2820 switch (hdev->discovery.type) {
2821 case DISCOV_TYPE_LE:
2822 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002823 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002824 break;
2825
2826 case DISCOV_TYPE_INTERLEAVED:
2827 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002828 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002829 break;
2830
2831 case DISCOV_TYPE_BREDR:
2832 break;
2833
2834 default:
2835 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2836 }
2837}
2838
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002839static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002840 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002841{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002842 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002843 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002844 struct hci_cp_le_set_scan_param param_cp;
2845 struct hci_cp_le_set_scan_enable enable_cp;
2846 struct hci_cp_inquiry inq_cp;
2847 struct hci_request req;
2848 /* General inquiry access code (GIAC) */
2849 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002850 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002851 int err;
2852
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002853 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002854
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002855 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002856
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002857 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002858 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002859 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002860 goto failed;
2861 }
2862
Andre Guedes642be6c2012-03-21 00:03:37 -03002863 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2864 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2865 MGMT_STATUS_BUSY);
2866 goto failed;
2867 }
2868
Johan Hedbergff9ef572012-01-04 14:23:45 +02002869 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002870 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002871 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002872 goto failed;
2873 }
2874
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002875 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002876 if (!cmd) {
2877 err = -ENOMEM;
2878 goto failed;
2879 }
2880
Andre Guedes4aab14e2012-02-17 20:39:36 -03002881 hdev->discovery.type = cp->type;
2882
Andre Guedes7c307722013-04-30 15:29:28 -03002883 hci_req_init(&req, hdev);
2884
Andre Guedes4aab14e2012-02-17 20:39:36 -03002885 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002886 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002887 status = mgmt_bredr_support(hdev);
2888 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002889 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002890 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002891 mgmt_pending_remove(cmd);
2892 goto failed;
2893 }
2894
Andre Guedes7c307722013-04-30 15:29:28 -03002895 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2896 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2897 MGMT_STATUS_BUSY);
2898 mgmt_pending_remove(cmd);
2899 goto failed;
2900 }
2901
2902 hci_inquiry_cache_flush(hdev);
2903
2904 memset(&inq_cp, 0, sizeof(inq_cp));
2905 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002906 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002907 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002908 break;
2909
2910 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002911 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002912 status = mgmt_le_support(hdev);
2913 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002914 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002915 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002916 mgmt_pending_remove(cmd);
2917 goto failed;
2918 }
2919
Andre Guedes7c307722013-04-30 15:29:28 -03002920 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002921 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002922 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2923 MGMT_STATUS_NOT_SUPPORTED);
2924 mgmt_pending_remove(cmd);
2925 goto failed;
2926 }
2927
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002928 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002929 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2930 MGMT_STATUS_REJECTED);
2931 mgmt_pending_remove(cmd);
2932 goto failed;
2933 }
2934
2935 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2936 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2937 MGMT_STATUS_BUSY);
2938 mgmt_pending_remove(cmd);
2939 goto failed;
2940 }
2941
2942 memset(&param_cp, 0, sizeof(param_cp));
2943 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002944 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2945 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002946 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2947 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2948 else
2949 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002950 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2951 &param_cp);
2952
2953 memset(&enable_cp, 0, sizeof(enable_cp));
2954 enable_cp.enable = LE_SCAN_ENABLE;
2955 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2956 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2957 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002958 break;
2959
Andre Guedesf39799f2012-02-17 20:39:35 -03002960 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002961 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2962 MGMT_STATUS_INVALID_PARAMS);
2963 mgmt_pending_remove(cmd);
2964 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002965 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002966
Andre Guedes7c307722013-04-30 15:29:28 -03002967 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002968 if (err < 0)
2969 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002970 else
2971 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002972
2973failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002974 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002975 return err;
2976}
2977
Andre Guedes1183fdc2013-04-30 15:29:35 -03002978static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2979{
2980 struct pending_cmd *cmd;
2981 int err;
2982
2983 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2984 if (!cmd)
2985 return -ENOENT;
2986
2987 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2988 &hdev->discovery.type, sizeof(hdev->discovery.type));
2989 mgmt_pending_remove(cmd);
2990
2991 return err;
2992}
2993
Andre Guedes0e05bba2013-04-30 15:29:33 -03002994static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2995{
2996 BT_DBG("status %d", status);
2997
2998 hci_dev_lock(hdev);
2999
3000 if (status) {
3001 mgmt_stop_discovery_failed(hdev, status);
3002 goto unlock;
3003 }
3004
3005 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3006
3007unlock:
3008 hci_dev_unlock(hdev);
3009}
3010
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003011static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003012 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003013{
Johan Hedbergd9306502012-02-20 23:25:18 +02003014 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003015 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003016 struct hci_cp_remote_name_req_cancel cp;
3017 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003018 struct hci_request req;
3019 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003020 int err;
3021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003022 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003023
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003024 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003025
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003026 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003027 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003028 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3029 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003030 goto unlock;
3031 }
3032
3033 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003034 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003035 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3036 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003037 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003038 }
3039
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003040 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003041 if (!cmd) {
3042 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003043 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003044 }
3045
Andre Guedes0e05bba2013-04-30 15:29:33 -03003046 hci_req_init(&req, hdev);
3047
Andre Guedese0d9727e2012-03-20 15:15:36 -03003048 switch (hdev->discovery.state) {
3049 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003050 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3051 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3052 } else {
3053 cancel_delayed_work(&hdev->le_scan_disable);
3054
3055 memset(&enable_cp, 0, sizeof(enable_cp));
3056 enable_cp.enable = LE_SCAN_DISABLE;
3057 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3058 sizeof(enable_cp), &enable_cp);
3059 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003060
Andre Guedese0d9727e2012-03-20 15:15:36 -03003061 break;
3062
3063 case DISCOVERY_RESOLVING:
3064 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003065 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003066 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003067 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003068 err = cmd_complete(sk, hdev->id,
3069 MGMT_OP_STOP_DISCOVERY, 0,
3070 &mgmt_cp->type,
3071 sizeof(mgmt_cp->type));
3072 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3073 goto unlock;
3074 }
3075
3076 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003077 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3078 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003079
3080 break;
3081
3082 default:
3083 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003084
3085 mgmt_pending_remove(cmd);
3086 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3087 MGMT_STATUS_FAILED, &mgmt_cp->type,
3088 sizeof(mgmt_cp->type));
3089 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003090 }
3091
Andre Guedes0e05bba2013-04-30 15:29:33 -03003092 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003093 if (err < 0)
3094 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003095 else
3096 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003097
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003098unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003099 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003100 return err;
3101}
3102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003103static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003104 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003105{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003106 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003107 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003108 int err;
3109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003110 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003111
Johan Hedberg561aafb2012-01-04 13:31:59 +02003112 hci_dev_lock(hdev);
3113
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003114 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003115 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003116 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003117 goto failed;
3118 }
3119
Johan Hedberga198e7b2012-02-17 14:27:06 +02003120 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003121 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003122 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003123 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003124 goto failed;
3125 }
3126
3127 if (cp->name_known) {
3128 e->name_state = NAME_KNOWN;
3129 list_del(&e->list);
3130 } else {
3131 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003132 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003133 }
3134
Johan Hedberge3846622013-01-09 15:29:33 +02003135 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3136 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003137
3138failed:
3139 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003140 return err;
3141}
3142
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003143static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003144 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003145{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003146 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003147 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003148 int err;
3149
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003150 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003151
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003152 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003153 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3154 MGMT_STATUS_INVALID_PARAMS,
3155 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003156
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003157 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003158
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003159 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003160 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003161 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003162 else
Szymon Janca6785be2012-12-13 15:11:21 +01003163 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003164
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003165 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003166 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003168 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003169
3170 return err;
3171}
3172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003173static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003174 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003175{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003176 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003177 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003178 int err;
3179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003180 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003181
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003182 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003183 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3184 MGMT_STATUS_INVALID_PARAMS,
3185 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003186
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003187 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003188
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003189 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003190 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003191 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003192 else
Szymon Janca6785be2012-12-13 15:11:21 +01003193 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003195 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003196 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003197
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003198 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003199
3200 return err;
3201}
3202
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003203static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3204 u16 len)
3205{
3206 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003207 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003208 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003209 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003210
3211 BT_DBG("%s", hdev->name);
3212
Szymon Jancc72d4b82012-03-16 16:02:57 +01003213 source = __le16_to_cpu(cp->source);
3214
3215 if (source > 0x0002)
3216 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3217 MGMT_STATUS_INVALID_PARAMS);
3218
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003219 hci_dev_lock(hdev);
3220
Szymon Jancc72d4b82012-03-16 16:02:57 +01003221 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003222 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3223 hdev->devid_product = __le16_to_cpu(cp->product);
3224 hdev->devid_version = __le16_to_cpu(cp->version);
3225
3226 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3227
Johan Hedberg890ea892013-03-15 17:06:52 -05003228 hci_req_init(&req, hdev);
3229 update_eir(&req);
3230 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003231
3232 hci_dev_unlock(hdev);
3233
3234 return err;
3235}
3236
Johan Hedberg4375f102013-09-25 13:26:10 +03003237static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3238{
3239 struct cmd_lookup match = { NULL, hdev };
3240
3241 if (status) {
3242 u8 mgmt_err = mgmt_status(status);
3243
3244 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3245 cmd_status_rsp, &mgmt_err);
3246 return;
3247 }
3248
3249 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3250 &match);
3251
3252 new_settings(hdev, match.sk);
3253
3254 if (match.sk)
3255 sock_put(match.sk);
3256}
3257
Marcel Holtmann21b51872013-10-10 09:47:53 -07003258static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3259 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003260{
3261 struct mgmt_mode *cp = data;
3262 struct pending_cmd *cmd;
3263 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003264 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003265 int err;
3266
3267 BT_DBG("request for %s", hdev->name);
3268
Johan Hedberge6fe7982013-10-02 15:45:22 +03003269 status = mgmt_le_support(hdev);
3270 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003271 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003272 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003273
3274 if (cp->val != 0x00 && cp->val != 0x01)
3275 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3276 MGMT_STATUS_INVALID_PARAMS);
3277
3278 hci_dev_lock(hdev);
3279
3280 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003281 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003282
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003283 /* The following conditions are ones which mean that we should
3284 * not do any HCI communication but directly send a mgmt
3285 * response to user space (after toggling the flag if
3286 * necessary).
3287 */
3288 if (!hdev_is_powered(hdev) || val == enabled ||
3289 hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECTED)) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003290 bool changed = false;
3291
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003292 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3293 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003294 changed = true;
3295 }
3296
3297 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3298 if (err < 0)
3299 goto unlock;
3300
3301 if (changed)
3302 err = new_settings(hdev, sk);
3303
3304 goto unlock;
3305 }
3306
3307 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3308 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3309 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3310 MGMT_STATUS_BUSY);
3311 goto unlock;
3312 }
3313
3314 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3315 if (!cmd) {
3316 err = -ENOMEM;
3317 goto unlock;
3318 }
3319
3320 hci_req_init(&req, hdev);
3321
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003322 if (val)
3323 enable_advertising(&req);
3324 else
3325 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003326
3327 err = hci_req_run(&req, set_advertising_complete);
3328 if (err < 0)
3329 mgmt_pending_remove(cmd);
3330
3331unlock:
3332 hci_dev_unlock(hdev);
3333 return err;
3334}
3335
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003336static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3337 void *data, u16 len)
3338{
3339 struct mgmt_cp_set_static_address *cp = data;
3340 int err;
3341
3342 BT_DBG("%s", hdev->name);
3343
Marcel Holtmann62af4442013-10-02 22:10:32 -07003344 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003345 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003346 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003347
3348 if (hdev_is_powered(hdev))
3349 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3350 MGMT_STATUS_REJECTED);
3351
3352 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3353 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3354 return cmd_status(sk, hdev->id,
3355 MGMT_OP_SET_STATIC_ADDRESS,
3356 MGMT_STATUS_INVALID_PARAMS);
3357
3358 /* Two most significant bits shall be set */
3359 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3360 return cmd_status(sk, hdev->id,
3361 MGMT_OP_SET_STATIC_ADDRESS,
3362 MGMT_STATUS_INVALID_PARAMS);
3363 }
3364
3365 hci_dev_lock(hdev);
3366
3367 bacpy(&hdev->static_addr, &cp->bdaddr);
3368
3369 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3370
3371 hci_dev_unlock(hdev);
3372
3373 return err;
3374}
3375
Johan Hedberg33e38b32013-03-15 17:07:05 -05003376static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3377{
3378 struct pending_cmd *cmd;
3379
3380 BT_DBG("status 0x%02x", status);
3381
3382 hci_dev_lock(hdev);
3383
3384 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3385 if (!cmd)
3386 goto unlock;
3387
3388 if (status) {
3389 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3390 mgmt_status(status));
3391 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003392 struct mgmt_mode *cp = cmd->param;
3393
3394 if (cp->val)
3395 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3396 else
3397 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3398
Johan Hedberg33e38b32013-03-15 17:07:05 -05003399 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3400 new_settings(hdev, cmd->sk);
3401 }
3402
3403 mgmt_pending_remove(cmd);
3404
3405unlock:
3406 hci_dev_unlock(hdev);
3407}
3408
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003409static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003410 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003411{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003412 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003413 struct pending_cmd *cmd;
3414 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003415 int err;
3416
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003417 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003418
Johan Hedberg56f87902013-10-02 13:43:13 +03003419 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3420 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003421 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3422 MGMT_STATUS_NOT_SUPPORTED);
3423
Johan Hedberga7e80f22013-01-09 16:05:19 +02003424 if (cp->val != 0x00 && cp->val != 0x01)
3425 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3426 MGMT_STATUS_INVALID_PARAMS);
3427
Johan Hedberg5400c042012-02-21 16:40:33 +02003428 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003429 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003430 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003431
3432 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003433 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003434 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003435
3436 hci_dev_lock(hdev);
3437
Johan Hedberg05cbf292013-03-15 17:07:07 -05003438 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3439 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3440 MGMT_STATUS_BUSY);
3441 goto unlock;
3442 }
3443
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003444 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3445 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3446 hdev);
3447 goto unlock;
3448 }
3449
Johan Hedberg33e38b32013-03-15 17:07:05 -05003450 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3451 data, len);
3452 if (!cmd) {
3453 err = -ENOMEM;
3454 goto unlock;
3455 }
3456
3457 hci_req_init(&req, hdev);
3458
Johan Hedberg406d7802013-03-15 17:07:09 -05003459 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003460
3461 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003462 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003463 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003464 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003465 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003466 }
3467
Johan Hedberg33e38b32013-03-15 17:07:05 -05003468unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003469 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003470
Antti Julkuf6422ec2011-06-22 13:11:56 +03003471 return err;
3472}
3473
Johan Hedberg0663ca22013-10-02 13:43:14 +03003474static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3475{
3476 struct pending_cmd *cmd;
3477
3478 BT_DBG("status 0x%02x", status);
3479
3480 hci_dev_lock(hdev);
3481
3482 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3483 if (!cmd)
3484 goto unlock;
3485
3486 if (status) {
3487 u8 mgmt_err = mgmt_status(status);
3488
3489 /* We need to restore the flag if related HCI commands
3490 * failed.
3491 */
3492 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3493
3494 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3495 } else {
3496 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3497 new_settings(hdev, cmd->sk);
3498 }
3499
3500 mgmt_pending_remove(cmd);
3501
3502unlock:
3503 hci_dev_unlock(hdev);
3504}
3505
3506static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3507{
3508 struct mgmt_mode *cp = data;
3509 struct pending_cmd *cmd;
3510 struct hci_request req;
3511 int err;
3512
3513 BT_DBG("request for %s", hdev->name);
3514
3515 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3516 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3517 MGMT_STATUS_NOT_SUPPORTED);
3518
3519 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3520 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3521 MGMT_STATUS_REJECTED);
3522
3523 if (cp->val != 0x00 && cp->val != 0x01)
3524 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3525 MGMT_STATUS_INVALID_PARAMS);
3526
3527 hci_dev_lock(hdev);
3528
3529 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3530 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3531 goto unlock;
3532 }
3533
3534 if (!hdev_is_powered(hdev)) {
3535 if (!cp->val) {
3536 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3537 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3538 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3539 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3540 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3541 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3542 }
3543
3544 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3545
3546 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3547 if (err < 0)
3548 goto unlock;
3549
3550 err = new_settings(hdev, sk);
3551 goto unlock;
3552 }
3553
3554 /* Reject disabling when powered on */
3555 if (!cp->val) {
3556 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3557 MGMT_STATUS_REJECTED);
3558 goto unlock;
3559 }
3560
3561 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3562 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3563 MGMT_STATUS_BUSY);
3564 goto unlock;
3565 }
3566
3567 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3568 if (!cmd) {
3569 err = -ENOMEM;
3570 goto unlock;
3571 }
3572
3573 /* We need to flip the bit already here so that hci_update_ad
3574 * generates the correct flags.
3575 */
3576 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3577
3578 hci_req_init(&req, hdev);
3579 hci_update_ad(&req);
3580 err = hci_req_run(&req, set_bredr_complete);
3581 if (err < 0)
3582 mgmt_pending_remove(cmd);
3583
3584unlock:
3585 hci_dev_unlock(hdev);
3586 return err;
3587}
3588
Johan Hedberg3f706b72013-01-20 14:27:16 +02003589static bool ltk_is_valid(struct mgmt_ltk_info *key)
3590{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003591 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3592 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003593 if (key->master != 0x00 && key->master != 0x01)
3594 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003595 if (!bdaddr_type_is_le(key->addr.type))
3596 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003597 return true;
3598}
3599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003600static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003601 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003602{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003603 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3604 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003605 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003606
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003607 BT_DBG("request for %s", hdev->name);
3608
3609 if (!lmp_le_capable(hdev))
3610 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3611 MGMT_STATUS_NOT_SUPPORTED);
3612
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003613 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003614
3615 expected_len = sizeof(*cp) + key_count *
3616 sizeof(struct mgmt_ltk_info);
3617 if (expected_len != len) {
3618 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003619 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003620 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003621 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003622 }
3623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003624 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003625
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003626 for (i = 0; i < key_count; i++) {
3627 struct mgmt_ltk_info *key = &cp->keys[i];
3628
Johan Hedberg3f706b72013-01-20 14:27:16 +02003629 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003630 return cmd_status(sk, hdev->id,
3631 MGMT_OP_LOAD_LONG_TERM_KEYS,
3632 MGMT_STATUS_INVALID_PARAMS);
3633 }
3634
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003635 hci_dev_lock(hdev);
3636
3637 hci_smp_ltks_clear(hdev);
3638
3639 for (i = 0; i < key_count; i++) {
3640 struct mgmt_ltk_info *key = &cp->keys[i];
3641 u8 type;
3642
3643 if (key->master)
3644 type = HCI_SMP_LTK;
3645 else
3646 type = HCI_SMP_LTK_SLAVE;
3647
Hemant Gupta4596fde2012-04-16 14:57:40 +05303648 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003649 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003650 type, 0, key->authenticated, key->val,
3651 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003652 }
3653
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003654 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3655 NULL, 0);
3656
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003657 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003658
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003659 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003660}
3661
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003662static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003663 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3664 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003665 bool var_len;
3666 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003667} mgmt_handlers[] = {
3668 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003669 { read_version, false, MGMT_READ_VERSION_SIZE },
3670 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3671 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3672 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3673 { set_powered, false, MGMT_SETTING_SIZE },
3674 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3675 { set_connectable, false, MGMT_SETTING_SIZE },
3676 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3677 { set_pairable, false, MGMT_SETTING_SIZE },
3678 { set_link_security, false, MGMT_SETTING_SIZE },
3679 { set_ssp, false, MGMT_SETTING_SIZE },
3680 { set_hs, false, MGMT_SETTING_SIZE },
3681 { set_le, false, MGMT_SETTING_SIZE },
3682 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3683 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3684 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3685 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3686 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3687 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3688 { disconnect, false, MGMT_DISCONNECT_SIZE },
3689 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3690 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3691 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3692 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3693 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3694 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3695 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3696 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3697 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3698 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3699 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3700 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3701 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3702 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3703 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3704 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3705 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3706 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3707 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003708 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003709 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003710 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003711 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003712};
3713
3714
Johan Hedberg03811012010-12-08 00:21:06 +02003715int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3716{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003717 void *buf;
3718 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003719 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003720 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003721 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003722 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003723 int err;
3724
3725 BT_DBG("got %zu bytes", msglen);
3726
3727 if (msglen < sizeof(*hdr))
3728 return -EINVAL;
3729
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003730 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003731 if (!buf)
3732 return -ENOMEM;
3733
3734 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3735 err = -EFAULT;
3736 goto done;
3737 }
3738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003739 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003740 opcode = __le16_to_cpu(hdr->opcode);
3741 index = __le16_to_cpu(hdr->index);
3742 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003743
3744 if (len != msglen - sizeof(*hdr)) {
3745 err = -EINVAL;
3746 goto done;
3747 }
3748
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003749 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003750 hdev = hci_dev_get(index);
3751 if (!hdev) {
3752 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003753 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003754 goto done;
3755 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003756
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003757 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3758 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003759 err = cmd_status(sk, index, opcode,
3760 MGMT_STATUS_INVALID_INDEX);
3761 goto done;
3762 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003763 }
3764
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003765 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003766 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003767 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003768 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003769 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003770 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003771 }
3772
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003773 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003774 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003775 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003776 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003777 goto done;
3778 }
3779
Johan Hedbergbe22b542012-03-01 22:24:41 +02003780 handler = &mgmt_handlers[opcode];
3781
3782 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003783 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003784 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003785 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003786 goto done;
3787 }
3788
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003789 if (hdev)
3790 mgmt_init_hdev(sk, hdev);
3791
3792 cp = buf + sizeof(*hdr);
3793
Johan Hedbergbe22b542012-03-01 22:24:41 +02003794 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003795 if (err < 0)
3796 goto done;
3797
Johan Hedberg03811012010-12-08 00:21:06 +02003798 err = msglen;
3799
3800done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003801 if (hdev)
3802 hci_dev_put(hdev);
3803
Johan Hedberg03811012010-12-08 00:21:06 +02003804 kfree(buf);
3805 return err;
3806}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003807
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003808void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003809{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003810 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003811 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003812
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003813 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003814}
3815
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003816void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003817{
Johan Hedberg5f159032012-03-02 03:13:19 +02003818 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003819
Marcel Holtmann1514b892013-10-06 08:25:01 -07003820 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003821 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003822
Johan Hedberg744cf192011-11-08 20:40:14 +02003823 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003824
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003825 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003826}
3827
Johan Hedberg890ea892013-03-15 17:06:52 -05003828static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003829{
Johan Hedberg890ea892013-03-15 17:06:52 -05003830 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003831 u8 scan = 0;
3832
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003833 /* Ensure that fast connectable is disabled. This function will
3834 * not do anything if the page scan parameters are already what
3835 * they should be.
3836 */
3837 write_fast_connectable(req, false);
3838
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003839 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3840 scan |= SCAN_PAGE;
3841 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3842 scan |= SCAN_INQUIRY;
3843
Johan Hedberg890ea892013-03-15 17:06:52 -05003844 if (scan)
3845 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003846}
3847
Johan Hedberg229ab392013-03-15 17:06:53 -05003848static void powered_complete(struct hci_dev *hdev, u8 status)
3849{
3850 struct cmd_lookup match = { NULL, hdev };
3851
3852 BT_DBG("status 0x%02x", status);
3853
3854 hci_dev_lock(hdev);
3855
3856 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3857
3858 new_settings(hdev, match.sk);
3859
3860 hci_dev_unlock(hdev);
3861
3862 if (match.sk)
3863 sock_put(match.sk);
3864}
3865
Johan Hedberg70da6242013-03-15 17:06:51 -05003866static int powered_update_hci(struct hci_dev *hdev)
3867{
Johan Hedberg890ea892013-03-15 17:06:52 -05003868 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003869 u8 link_sec;
3870
Johan Hedberg890ea892013-03-15 17:06:52 -05003871 hci_req_init(&req, hdev);
3872
Johan Hedberg70da6242013-03-15 17:06:51 -05003873 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3874 !lmp_host_ssp_capable(hdev)) {
3875 u8 ssp = 1;
3876
Johan Hedberg890ea892013-03-15 17:06:52 -05003877 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003878 }
3879
Johan Hedbergc73eee92013-04-19 18:35:21 +03003880 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3881 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003882 struct hci_cp_write_le_host_supported cp;
3883
3884 cp.le = 1;
3885 cp.simul = lmp_le_br_capable(hdev);
3886
3887 /* Check first if we already have the right
3888 * host state (host features set)
3889 */
3890 if (cp.le != lmp_host_le_capable(hdev) ||
3891 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003892 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3893 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003894
3895 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3896 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003897 }
3898
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003899 if (lmp_le_capable(hdev)) {
3900 /* Set random address to static address if configured */
3901 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3902 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3903 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003904
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003905 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3906 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003907 }
3908
Johan Hedberg70da6242013-03-15 17:06:51 -05003909 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3910 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003911 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3912 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003913
3914 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003915 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3916 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003917 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003918 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003919 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003920 }
3921
Johan Hedberg229ab392013-03-15 17:06:53 -05003922 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003923}
3924
Johan Hedberg744cf192011-11-08 20:40:14 +02003925int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003926{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003927 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003928 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3929 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003930 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003931
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003932 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3933 return 0;
3934
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003935 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003936 if (powered_update_hci(hdev) == 0)
3937 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003938
Johan Hedberg229ab392013-03-15 17:06:53 -05003939 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3940 &match);
3941 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003942 }
3943
Johan Hedberg229ab392013-03-15 17:06:53 -05003944 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3945 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3946
3947 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3948 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3949 zero_cod, sizeof(zero_cod), NULL);
3950
3951new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003952 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003953
3954 if (match.sk)
3955 sock_put(match.sk);
3956
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003957 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003958}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003959
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003960void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03003961{
3962 struct pending_cmd *cmd;
3963 u8 status;
3964
3965 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3966 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003967 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03003968
3969 if (err == -ERFKILL)
3970 status = MGMT_STATUS_RFKILLED;
3971 else
3972 status = MGMT_STATUS_FAILED;
3973
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003974 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03003975
3976 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03003977}
3978
Johan Hedberg744cf192011-11-08 20:40:14 +02003979int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003980{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003981 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003982 bool changed = false;
3983 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003984
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003985 if (discoverable) {
3986 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3987 changed = true;
3988 } else {
3989 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3990 changed = true;
3991 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003992
Johan Hedberged9b5f22012-02-21 20:47:06 +02003993 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003994 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003995
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003996 if (changed)
3997 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003998
Johan Hedberg73f22f62010-12-29 16:00:25 +02003999 if (match.sk)
4000 sock_put(match.sk);
4001
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004002 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004003}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004004
Johan Hedberg744cf192011-11-08 20:40:14 +02004005int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004006{
Johan Hedberg2b76f452013-03-15 17:07:04 -05004007 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004008 bool changed = false;
4009 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004010
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004011 if (connectable) {
4012 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4013 changed = true;
4014 } else {
4015 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4016 changed = true;
4017 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004018
Johan Hedberg2b76f452013-03-15 17:07:04 -05004019 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004020
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004021 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004022 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004023
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004024 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004025}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004026
Johan Hedberg744cf192011-11-08 20:40:14 +02004027int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004028{
Johan Hedbergca69b792011-11-11 18:10:00 +02004029 u8 mgmt_err = mgmt_status(status);
4030
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004031 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004032 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004033 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004034
4035 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004036 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004037 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004038
4039 return 0;
4040}
4041
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004042int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4043 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004044{
Johan Hedberg86742e12011-11-07 23:13:38 +02004045 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004046
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004047 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004048
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004049 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004050 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004051 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004052 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004053 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004054 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004055
Johan Hedberg744cf192011-11-08 20:40:14 +02004056 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004057}
Johan Hedbergf7520542011-01-20 12:34:39 +02004058
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004059int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4060{
4061 struct mgmt_ev_new_long_term_key ev;
4062
4063 memset(&ev, 0, sizeof(ev));
4064
4065 ev.store_hint = persistent;
4066 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004067 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004068 ev.key.authenticated = key->authenticated;
4069 ev.key.enc_size = key->enc_size;
4070 ev.key.ediv = key->ediv;
4071
4072 if (key->type == HCI_SMP_LTK)
4073 ev.key.master = 1;
4074
4075 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4076 memcpy(ev.key.val, key->val, sizeof(key->val));
4077
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004078 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4079 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004080}
4081
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004082void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4083 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4084 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004085{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004086 char buf[512];
4087 struct mgmt_ev_device_connected *ev = (void *) buf;
4088 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004089
Johan Hedbergb644ba32012-01-17 21:48:47 +02004090 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004091 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004092
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004093 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004094
Johan Hedbergb644ba32012-01-17 21:48:47 +02004095 if (name_len > 0)
4096 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004097 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004098
4099 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004100 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004101 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004102
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004103 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004104
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004105 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4106 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004107}
4108
Johan Hedberg8962ee72011-01-20 12:40:27 +02004109static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4110{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004111 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004112 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004113 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004114
Johan Hedberg88c3df12012-02-09 14:27:38 +02004115 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4116 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004117
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004118 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004119 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004120
4121 *sk = cmd->sk;
4122 sock_hold(*sk);
4123
Johan Hedberga664b5b2011-02-19 12:06:02 -03004124 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004125}
4126
Johan Hedberg124f6e32012-02-09 13:50:12 +02004127static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004128{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004129 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004130 struct mgmt_cp_unpair_device *cp = cmd->param;
4131 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004132
4133 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004134 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4135 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004136
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004137 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4138
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004139 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004140
4141 mgmt_pending_remove(cmd);
4142}
4143
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004144void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4145 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004146{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004147 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004148 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004149
Johan Hedberg744cf192011-11-08 20:40:14 +02004150 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004151
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004152 bacpy(&ev.addr.bdaddr, bdaddr);
4153 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4154 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004155
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004156 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004157
4158 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004159 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004160
Johan Hedberg124f6e32012-02-09 13:50:12 +02004161 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004162 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004163}
4164
Marcel Holtmann78929242013-10-06 23:55:47 -07004165void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4166 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004167{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004168 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004169 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004170
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004171 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4172 hdev);
4173
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004174 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004175 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004176 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004177
Johan Hedberg88c3df12012-02-09 14:27:38 +02004178 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004179 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004180
Marcel Holtmann78929242013-10-06 23:55:47 -07004181 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4182 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004183
Johan Hedberga664b5b2011-02-19 12:06:02 -03004184 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004185}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004186
Marcel Holtmann445608d2013-10-06 23:55:48 -07004187void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4188 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004189{
4190 struct mgmt_ev_connect_failed ev;
4191
Johan Hedberg4c659c32011-11-07 23:13:39 +02004192 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004193 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004194 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004195
Marcel Holtmann445608d2013-10-06 23:55:48 -07004196 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004197}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004198
Johan Hedberg744cf192011-11-08 20:40:14 +02004199int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004200{
4201 struct mgmt_ev_pin_code_request ev;
4202
Johan Hedbergd8457692012-02-17 14:24:57 +02004203 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004204 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004205 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004206
Johan Hedberg744cf192011-11-08 20:40:14 +02004207 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004208 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004209}
4210
Johan Hedberg744cf192011-11-08 20:40:14 +02004211int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004212 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004213{
4214 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004215 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004216 int err;
4217
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004218 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004219 if (!cmd)
4220 return -ENOENT;
4221
Johan Hedbergd8457692012-02-17 14:24:57 +02004222 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004223 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004224
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004225 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004226 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004227
Johan Hedberga664b5b2011-02-19 12:06:02 -03004228 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004229
4230 return err;
4231}
4232
Johan Hedberg744cf192011-11-08 20:40:14 +02004233int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004234 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004235{
4236 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004237 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004238 int err;
4239
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004240 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004241 if (!cmd)
4242 return -ENOENT;
4243
Johan Hedbergd8457692012-02-17 14:24:57 +02004244 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004245 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004246
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004247 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004248 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004249
Johan Hedberga664b5b2011-02-19 12:06:02 -03004250 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004251
4252 return err;
4253}
Johan Hedberga5c29682011-02-19 12:05:57 -03004254
Johan Hedberg744cf192011-11-08 20:40:14 +02004255int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004256 u8 link_type, u8 addr_type, __le32 value,
4257 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004258{
4259 struct mgmt_ev_user_confirm_request ev;
4260
Johan Hedberg744cf192011-11-08 20:40:14 +02004261 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004262
Johan Hedberg272d90d2012-02-09 15:26:12 +02004263 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004264 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004265 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004266 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004267
Johan Hedberg744cf192011-11-08 20:40:14 +02004268 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004269 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004270}
4271
Johan Hedberg272d90d2012-02-09 15:26:12 +02004272int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004273 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004274{
4275 struct mgmt_ev_user_passkey_request ev;
4276
4277 BT_DBG("%s", hdev->name);
4278
Johan Hedberg272d90d2012-02-09 15:26:12 +02004279 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004280 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004281
4282 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004283 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004284}
4285
Brian Gix0df4c182011-11-16 13:53:13 -08004286static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004287 u8 link_type, u8 addr_type, u8 status,
4288 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004289{
4290 struct pending_cmd *cmd;
4291 struct mgmt_rp_user_confirm_reply rp;
4292 int err;
4293
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004294 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004295 if (!cmd)
4296 return -ENOENT;
4297
Johan Hedberg272d90d2012-02-09 15:26:12 +02004298 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004299 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004300 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004301 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004302
Johan Hedberga664b5b2011-02-19 12:06:02 -03004303 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004304
4305 return err;
4306}
4307
Johan Hedberg744cf192011-11-08 20:40:14 +02004308int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004309 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004310{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004311 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004312 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004313}
4314
Johan Hedberg272d90d2012-02-09 15:26:12 +02004315int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004316 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004317{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004318 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004319 status,
4320 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004321}
Johan Hedberg2a611692011-02-19 12:06:00 -03004322
Brian Gix604086b2011-11-23 08:28:33 -08004323int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004324 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004325{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004326 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004327 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004328}
4329
Johan Hedberg272d90d2012-02-09 15:26:12 +02004330int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004331 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004332{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004333 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004334 status,
4335 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004336}
4337
Johan Hedberg92a25252012-09-06 18:39:26 +03004338int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4339 u8 link_type, u8 addr_type, u32 passkey,
4340 u8 entered)
4341{
4342 struct mgmt_ev_passkey_notify ev;
4343
4344 BT_DBG("%s", hdev->name);
4345
4346 bacpy(&ev.addr.bdaddr, bdaddr);
4347 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4348 ev.passkey = __cpu_to_le32(passkey);
4349 ev.entered = entered;
4350
4351 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4352}
4353
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004354int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004355 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004356{
4357 struct mgmt_ev_auth_failed ev;
4358
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004359 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004360 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004361 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004362
Johan Hedberg744cf192011-11-08 20:40:14 +02004363 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004364}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004365
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004366int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4367{
4368 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004369 bool changed = false;
4370 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004371
4372 if (status) {
4373 u8 mgmt_err = mgmt_status(status);
4374 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004375 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004376 return 0;
4377 }
4378
Johan Hedberg47990ea2012-02-22 11:58:37 +02004379 if (test_bit(HCI_AUTH, &hdev->flags)) {
4380 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4381 changed = true;
4382 } else {
4383 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4384 changed = true;
4385 }
4386
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004387 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004388 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004389
Johan Hedberg47990ea2012-02-22 11:58:37 +02004390 if (changed)
4391 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004392
4393 if (match.sk)
4394 sock_put(match.sk);
4395
4396 return err;
4397}
4398
Johan Hedberg890ea892013-03-15 17:06:52 -05004399static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004400{
Johan Hedberg890ea892013-03-15 17:06:52 -05004401 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004402 struct hci_cp_write_eir cp;
4403
Johan Hedberg976eb202012-10-24 21:12:01 +03004404 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004405 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004406
Johan Hedbergc80da272012-02-22 15:38:48 +02004407 memset(hdev->eir, 0, sizeof(hdev->eir));
4408
Johan Hedbergcacaf522012-02-21 00:52:42 +02004409 memset(&cp, 0, sizeof(cp));
4410
Johan Hedberg890ea892013-03-15 17:06:52 -05004411 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004412}
4413
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004414int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004415{
4416 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004417 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004418 bool changed = false;
4419 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004420
4421 if (status) {
4422 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004423
4424 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004425 &hdev->dev_flags)) {
4426 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004427 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004428 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004429
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004430 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4431 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004432
4433 return err;
4434 }
4435
4436 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004437 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004438 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004439 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4440 if (!changed)
4441 changed = test_and_clear_bit(HCI_HS_ENABLED,
4442 &hdev->dev_flags);
4443 else
4444 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004445 }
4446
4447 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4448
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004449 if (changed)
4450 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004451
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004452 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004453 sock_put(match.sk);
4454
Johan Hedberg890ea892013-03-15 17:06:52 -05004455 hci_req_init(&req, hdev);
4456
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004457 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004458 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004459 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004460 clear_eir(&req);
4461
4462 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004463
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004464 return err;
4465}
4466
Johan Hedberg92da6092013-03-15 17:06:55 -05004467static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004468{
4469 struct cmd_lookup *match = data;
4470
Johan Hedberg90e70452012-02-23 23:09:40 +02004471 if (match->sk == NULL) {
4472 match->sk = cmd->sk;
4473 sock_hold(match->sk);
4474 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004475}
4476
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004477int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004478 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004479{
Johan Hedberg90e70452012-02-23 23:09:40 +02004480 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4481 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004482
Johan Hedberg92da6092013-03-15 17:06:55 -05004483 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4484 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4485 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004486
4487 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004488 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4489 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004490
4491 if (match.sk)
4492 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004493
4494 return err;
4495}
4496
Johan Hedberg744cf192011-11-08 20:40:14 +02004497int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004498{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004499 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004500 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004501
Johan Hedberg13928972013-03-15 17:07:00 -05004502 if (status)
4503 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004504
4505 memset(&ev, 0, sizeof(ev));
4506 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004507 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004508
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004509 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004510 if (!cmd) {
4511 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004512
Johan Hedberg13928972013-03-15 17:07:00 -05004513 /* If this is a HCI command related to powering on the
4514 * HCI dev don't send any mgmt signals.
4515 */
4516 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4517 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004518 }
4519
Johan Hedberg13928972013-03-15 17:07:00 -05004520 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4521 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004522}
Szymon Jancc35938b2011-03-22 13:12:21 +01004523
Johan Hedberg744cf192011-11-08 20:40:14 +02004524int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004525 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004526{
4527 struct pending_cmd *cmd;
4528 int err;
4529
Johan Hedberg744cf192011-11-08 20:40:14 +02004530 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004531
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004532 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004533 if (!cmd)
4534 return -ENOENT;
4535
4536 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004537 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4538 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004539 } else {
4540 struct mgmt_rp_read_local_oob_data rp;
4541
4542 memcpy(rp.hash, hash, sizeof(rp.hash));
4543 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4544
Johan Hedberg744cf192011-11-08 20:40:14 +02004545 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004546 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4547 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004548 }
4549
4550 mgmt_pending_remove(cmd);
4551
4552 return err;
4553}
Johan Hedberge17acd42011-03-30 23:57:16 +03004554
Marcel Holtmann901801b2013-10-06 23:55:51 -07004555void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4556 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4557 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004558{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004559 char buf[512];
4560 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004561 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004562
Andre Guedes12602d02013-04-30 15:29:40 -03004563 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004564 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004565
Johan Hedberg1dc06092012-01-15 21:01:23 +02004566 /* Leave 5 bytes for a potential CoD field */
4567 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004568 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004569
Johan Hedberg1dc06092012-01-15 21:01:23 +02004570 memset(buf, 0, sizeof(buf));
4571
Johan Hedberge319d2e2012-01-15 19:51:59 +02004572 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004573 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004574 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004575 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304576 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004577 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304578 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004579
Johan Hedberg1dc06092012-01-15 21:01:23 +02004580 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004581 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004582
Johan Hedberg1dc06092012-01-15 21:01:23 +02004583 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4584 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004585 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004586
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004587 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004588 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004589
Marcel Holtmann901801b2013-10-06 23:55:51 -07004590 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004591}
Johan Hedberga88a9652011-03-30 13:18:12 +03004592
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004593void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4594 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004595{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004596 struct mgmt_ev_device_found *ev;
4597 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4598 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004599
Johan Hedbergb644ba32012-01-17 21:48:47 +02004600 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004601
Johan Hedbergb644ba32012-01-17 21:48:47 +02004602 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004603
Johan Hedbergb644ba32012-01-17 21:48:47 +02004604 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004605 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004606 ev->rssi = rssi;
4607
4608 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004609 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004610
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004611 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004612
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004613 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004614}
Johan Hedberg314b2382011-04-27 10:29:57 -04004615
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004616void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004617{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004618 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004619 struct pending_cmd *cmd;
4620
Andre Guedes343fb142011-11-22 17:14:19 -03004621 BT_DBG("%s discovering %u", hdev->name, discovering);
4622
Johan Hedberg164a6e72011-11-01 17:06:44 +02004623 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004624 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004625 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004626 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004627
4628 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004629 u8 type = hdev->discovery.type;
4630
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004631 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4632 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004633 mgmt_pending_remove(cmd);
4634 }
4635
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004636 memset(&ev, 0, sizeof(ev));
4637 ev.type = hdev->discovery.type;
4638 ev.discovering = discovering;
4639
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004640 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004641}
Antti Julku5e762442011-08-25 16:48:02 +03004642
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004643int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004644{
4645 struct pending_cmd *cmd;
4646 struct mgmt_ev_device_blocked ev;
4647
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004648 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004649
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004650 bacpy(&ev.addr.bdaddr, bdaddr);
4651 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004652
Johan Hedberg744cf192011-11-08 20:40:14 +02004653 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004654 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004655}
4656
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004657int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004658{
4659 struct pending_cmd *cmd;
4660 struct mgmt_ev_device_unblocked ev;
4661
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004662 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004663
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004664 bacpy(&ev.addr.bdaddr, bdaddr);
4665 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004666
Johan Hedberg744cf192011-11-08 20:40:14 +02004667 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004668 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004669}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004670
4671static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4672{
4673 BT_DBG("%s status %u", hdev->name, status);
4674
4675 /* Clear the advertising mgmt setting if we failed to re-enable it */
4676 if (status) {
4677 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004678 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004679 }
4680}
4681
4682void mgmt_reenable_advertising(struct hci_dev *hdev)
4683{
4684 struct hci_request req;
4685
4686 if (hdev->conn_hash.le_num)
4687 return;
4688
4689 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4690 return;
4691
4692 hci_req_init(&req, hdev);
4693 enable_advertising(&req);
4694
4695 /* If this fails we have no option but to let user space know
4696 * that we've disabled advertising.
4697 */
4698 if (hci_req_run(&req, adv_enable_complete) < 0) {
4699 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004700 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004701 }
4702}