blob: 7d25d6dcd79d5ee005a3357165387d3ef3adab76 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg2da9c552012-02-17 14:39:28 +020035#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070036#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020037
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070076 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030077 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030078 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070079 MGMT_OP_SET_STATIC_ADDRESS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020080};
81
82static const u16 mgmt_events[] = {
83 MGMT_EV_CONTROLLER_ERROR,
84 MGMT_EV_INDEX_ADDED,
85 MGMT_EV_INDEX_REMOVED,
86 MGMT_EV_NEW_SETTINGS,
87 MGMT_EV_CLASS_OF_DEV_CHANGED,
88 MGMT_EV_LOCAL_NAME_CHANGED,
89 MGMT_EV_NEW_LINK_KEY,
90 MGMT_EV_NEW_LONG_TERM_KEY,
91 MGMT_EV_DEVICE_CONNECTED,
92 MGMT_EV_DEVICE_DISCONNECTED,
93 MGMT_EV_CONNECT_FAILED,
94 MGMT_EV_PIN_CODE_REQUEST,
95 MGMT_EV_USER_CONFIRM_REQUEST,
96 MGMT_EV_USER_PASSKEY_REQUEST,
97 MGMT_EV_AUTH_FAILED,
98 MGMT_EV_DEVICE_FOUND,
99 MGMT_EV_DISCOVERING,
100 MGMT_EV_DEVICE_BLOCKED,
101 MGMT_EV_DEVICE_UNBLOCKED,
102 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300103 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200104};
105
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800106#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200107
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200108#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
109 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
110
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200111struct pending_cmd {
112 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200113 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100115 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300117 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118};
119
Johan Hedbergca69b792011-11-11 18:10:00 +0200120/* HCI to MGMT error code conversion table */
121static u8 mgmt_status_table[] = {
122 MGMT_STATUS_SUCCESS,
123 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
124 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
125 MGMT_STATUS_FAILED, /* Hardware Failure */
126 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
127 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
128 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
129 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
130 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
132 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
133 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
134 MGMT_STATUS_BUSY, /* Command Disallowed */
135 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
136 MGMT_STATUS_REJECTED, /* Rejected Security */
137 MGMT_STATUS_REJECTED, /* Rejected Personal */
138 MGMT_STATUS_TIMEOUT, /* Host Timeout */
139 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
140 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
141 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
142 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
143 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
144 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
145 MGMT_STATUS_BUSY, /* Repeated Attempts */
146 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
147 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
148 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
149 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
150 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
151 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
153 MGMT_STATUS_FAILED, /* Unspecified Error */
154 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
155 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
156 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
157 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
158 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
159 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
160 MGMT_STATUS_FAILED, /* Unit Link Key Used */
161 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
162 MGMT_STATUS_TIMEOUT, /* Instant Passed */
163 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
164 MGMT_STATUS_FAILED, /* Transaction Collision */
165 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
166 MGMT_STATUS_REJECTED, /* QoS Rejected */
167 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
168 MGMT_STATUS_REJECTED, /* Insufficient Security */
169 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
170 MGMT_STATUS_BUSY, /* Role Switch Pending */
171 MGMT_STATUS_FAILED, /* Slot Violation */
172 MGMT_STATUS_FAILED, /* Role Switch Failed */
173 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
174 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
175 MGMT_STATUS_BUSY, /* Host Busy Pairing */
176 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
177 MGMT_STATUS_BUSY, /* Controller Busy */
178 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
179 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
180 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
181 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
182 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
183};
184
185static u8 mgmt_status(u8 hci_status)
186{
187 if (hci_status < ARRAY_SIZE(mgmt_status_table))
188 return mgmt_status_table[hci_status];
189
190 return MGMT_STATUS_FAILED;
191}
192
Szymon Janc4e51eae2011-02-25 19:05:48 +0100193static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200194{
195 struct sk_buff *skb;
196 struct mgmt_hdr *hdr;
197 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300198 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200199
Szymon Janc34eb5252011-02-28 14:10:08 +0100200 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Andre Guedes790eff42012-06-07 19:05:46 -0300202 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203 if (!skb)
204 return -ENOMEM;
205
206 hdr = (void *) skb_put(skb, sizeof(*hdr));
207
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530208 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100209 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200210 hdr->len = cpu_to_le16(sizeof(*ev));
211
212 ev = (void *) skb_put(skb, sizeof(*ev));
213 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200214 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200215
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300216 err = sock_queue_rcv_skb(sk, skb);
217 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200218 kfree_skb(skb);
219
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300220 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221}
222
Johan Hedbergaee9b212012-02-18 15:07:59 +0200223static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300224 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200225{
226 struct sk_buff *skb;
227 struct mgmt_hdr *hdr;
228 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200230
231 BT_DBG("sock %p", sk);
232
Andre Guedes790eff42012-06-07 19:05:46 -0300233 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200234 if (!skb)
235 return -ENOMEM;
236
237 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200238
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530239 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100240 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200241 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200242
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200244 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200245 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100246
247 if (rp)
248 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200249
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300250 err = sock_queue_rcv_skb(sk, skb);
251 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 kfree_skb(skb);
253
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100254 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200255}
256
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300257static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
258 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200259{
260 struct mgmt_rp_read_version rp;
261
262 BT_DBG("sock %p", sk);
263
264 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200265 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200266
Johan Hedbergaee9b212012-02-18 15:07:59 +0200267 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300268 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200269}
270
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
272 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200273{
274 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200275 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
276 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200277 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200278 size_t rp_size;
279 int i, err;
280
281 BT_DBG("sock %p", sk);
282
283 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
284
285 rp = kmalloc(rp_size, GFP_KERNEL);
286 if (!rp)
287 return -ENOMEM;
288
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200289 rp->num_commands = __constant_cpu_to_le16(num_commands);
290 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200291
292 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
293 put_unaligned_le16(mgmt_commands[i], opcode);
294
295 for (i = 0; i < num_events; i++, opcode++)
296 put_unaligned_le16(mgmt_events[i], opcode);
297
Johan Hedbergaee9b212012-02-18 15:07:59 +0200298 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300299 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200300 kfree(rp);
301
302 return err;
303}
304
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300305static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
306 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200307{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200308 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200309 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200310 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300312 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313
314 BT_DBG("sock %p", sk);
315
316 read_lock(&hci_dev_list_lock);
317
318 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300319 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700320 if (d->dev_type == HCI_BREDR)
321 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 }
323
Johan Hedberga38528f2011-01-22 06:46:43 +0200324 rp_len = sizeof(*rp) + (2 * count);
325 rp = kmalloc(rp_len, GFP_ATOMIC);
326 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100327 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330
Johan Hedberg476e44c2012-10-19 20:10:46 +0300331 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200332 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200333 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200334 continue;
335
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700336 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
337 continue;
338
Marcel Holtmann1514b892013-10-06 08:25:01 -0700339 if (d->dev_type == HCI_BREDR) {
340 rp->index[count++] = cpu_to_le16(d->id);
341 BT_DBG("Added hci%u", d->id);
342 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343 }
344
Johan Hedberg476e44c2012-10-19 20:10:46 +0300345 rp->num_controllers = cpu_to_le16(count);
346 rp_len = sizeof(*rp) + (2 * count);
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 read_unlock(&hci_dev_list_lock);
349
Johan Hedbergaee9b212012-02-18 15:07:59 +0200350 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300351 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352
Johan Hedberga38528f2011-01-22 06:46:43 +0200353 kfree(rp);
354
355 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356}
357
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200358static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200359{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200364
Andre Guedes9a1a1992012-07-24 15:03:48 -0300365 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200367
Andre Guedesed3fa312012-07-24 15:03:46 -0300368 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300369 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500370 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
371 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300372 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 settings |= MGMT_SETTING_BREDR;
374 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100375 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700376 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100377
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300378 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200379 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300380 settings |= MGMT_SETTING_ADVERTISING;
381 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200382
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200383 return settings;
384}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200385
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200386static u32 get_current_settings(struct hci_dev *hdev)
387{
388 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200389
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200390 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100391 settings |= MGMT_SETTING_POWERED;
392
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200393 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394 settings |= MGMT_SETTING_CONNECTABLE;
395
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500396 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
397 settings |= MGMT_SETTING_FAST_CONNECTABLE;
398
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200399 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 settings |= MGMT_SETTING_DISCOVERABLE;
401
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200402 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_PAIRABLE;
404
Johan Hedberg56f87902013-10-02 13:43:13 +0300405 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_BREDR;
407
Johan Hedberg06199cf2012-02-22 16:37:11 +0200408 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200410
Johan Hedberg47990ea2012-02-22 11:58:37 +0200411 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200414 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200417 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
418 settings |= MGMT_SETTING_HS;
419
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200420 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300421 settings |= MGMT_SETTING_ADVERTISING;
422
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200424}
425
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300426#define PNP_INFO_SVCLASS_ID 0x1200
427
Johan Hedberg213202e2013-01-27 00:31:33 +0200428static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
429{
430 u8 *ptr = data, *uuids_start = NULL;
431 struct bt_uuid *uuid;
432
433 if (len < 4)
434 return ptr;
435
436 list_for_each_entry(uuid, &hdev->uuids, list) {
437 u16 uuid16;
438
439 if (uuid->size != 16)
440 continue;
441
442 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
443 if (uuid16 < 0x1100)
444 continue;
445
446 if (uuid16 == PNP_INFO_SVCLASS_ID)
447 continue;
448
449 if (!uuids_start) {
450 uuids_start = ptr;
451 uuids_start[0] = 1;
452 uuids_start[1] = EIR_UUID16_ALL;
453 ptr += 2;
454 }
455
456 /* Stop if not enough space to put next UUID */
457 if ((ptr - data) + sizeof(u16) > len) {
458 uuids_start[1] = EIR_UUID16_SOME;
459 break;
460 }
461
462 *ptr++ = (uuid16 & 0x00ff);
463 *ptr++ = (uuid16 & 0xff00) >> 8;
464 uuids_start[0] += sizeof(uuid16);
465 }
466
467 return ptr;
468}
469
Johan Hedbergcdf19632013-01-27 00:31:34 +0200470static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
471{
472 u8 *ptr = data, *uuids_start = NULL;
473 struct bt_uuid *uuid;
474
475 if (len < 6)
476 return ptr;
477
478 list_for_each_entry(uuid, &hdev->uuids, list) {
479 if (uuid->size != 32)
480 continue;
481
482 if (!uuids_start) {
483 uuids_start = ptr;
484 uuids_start[0] = 1;
485 uuids_start[1] = EIR_UUID32_ALL;
486 ptr += 2;
487 }
488
489 /* Stop if not enough space to put next UUID */
490 if ((ptr - data) + sizeof(u32) > len) {
491 uuids_start[1] = EIR_UUID32_SOME;
492 break;
493 }
494
495 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
496 ptr += sizeof(u32);
497 uuids_start[0] += sizeof(u32);
498 }
499
500 return ptr;
501}
502
Johan Hedbergc00d5752013-01-27 00:31:35 +0200503static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
504{
505 u8 *ptr = data, *uuids_start = NULL;
506 struct bt_uuid *uuid;
507
508 if (len < 18)
509 return ptr;
510
511 list_for_each_entry(uuid, &hdev->uuids, list) {
512 if (uuid->size != 128)
513 continue;
514
515 if (!uuids_start) {
516 uuids_start = ptr;
517 uuids_start[0] = 1;
518 uuids_start[1] = EIR_UUID128_ALL;
519 ptr += 2;
520 }
521
522 /* Stop if not enough space to put next UUID */
523 if ((ptr - data) + 16 > len) {
524 uuids_start[1] = EIR_UUID128_SOME;
525 break;
526 }
527
528 memcpy(ptr, uuid->uuid, 16);
529 ptr += 16;
530 uuids_start[0] += 16;
531 }
532
533 return ptr;
534}
535
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300536static void create_eir(struct hci_dev *hdev, u8 *data)
537{
538 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 size_t name_len;
540
541 name_len = strlen(hdev->dev_name);
542
543 if (name_len > 0) {
544 /* EIR Data type */
545 if (name_len > 48) {
546 name_len = 48;
547 ptr[1] = EIR_NAME_SHORT;
548 } else
549 ptr[1] = EIR_NAME_COMPLETE;
550
551 /* EIR Data length */
552 ptr[0] = name_len + 1;
553
554 memcpy(ptr + 2, hdev->dev_name, name_len);
555
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300556 ptr += (name_len + 2);
557 }
558
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100559 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700560 ptr[0] = 2;
561 ptr[1] = EIR_TX_POWER;
562 ptr[2] = (u8) hdev->inq_tx_power;
563
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700564 ptr += 3;
565 }
566
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700567 if (hdev->devid_source > 0) {
568 ptr[0] = 9;
569 ptr[1] = EIR_DEVICE_ID;
570
571 put_unaligned_le16(hdev->devid_source, ptr + 2);
572 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
573 put_unaligned_le16(hdev->devid_product, ptr + 6);
574 put_unaligned_le16(hdev->devid_version, ptr + 8);
575
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700576 ptr += 10;
577 }
578
Johan Hedberg213202e2013-01-27 00:31:33 +0200579 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200580 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200581 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300582}
583
Johan Hedberg890ea892013-03-15 17:06:52 -0500584static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300585{
Johan Hedberg890ea892013-03-15 17:06:52 -0500586 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300587 struct hci_cp_write_eir cp;
588
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200589 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500590 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200591
Johan Hedberg976eb202012-10-24 21:12:01 +0300592 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500593 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300594
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200595 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500596 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300597
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200598 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500599 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300600
601 memset(&cp, 0, sizeof(cp));
602
603 create_eir(hdev, cp.data);
604
605 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500606 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300607
608 memcpy(hdev->eir, cp.data, sizeof(cp.data));
609
Johan Hedberg890ea892013-03-15 17:06:52 -0500610 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300611}
612
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200613static u8 get_service_classes(struct hci_dev *hdev)
614{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300615 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200616 u8 val = 0;
617
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300618 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200619 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620
621 return val;
622}
623
Johan Hedberg890ea892013-03-15 17:06:52 -0500624static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200625{
Johan Hedberg890ea892013-03-15 17:06:52 -0500626 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627 u8 cod[3];
628
629 BT_DBG("%s", hdev->name);
630
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200631 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500632 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200633
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200634 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500635 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200636
637 cod[0] = hdev->minor_class;
638 cod[1] = hdev->major_class;
639 cod[2] = get_service_classes(hdev);
640
641 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500642 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200643
Johan Hedberg890ea892013-03-15 17:06:52 -0500644 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200645}
646
Johan Hedberg7d785252011-12-15 00:47:39 +0200647static void service_cache_off(struct work_struct *work)
648{
649 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300650 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500651 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200652
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200653 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200654 return;
655
Johan Hedberg890ea892013-03-15 17:06:52 -0500656 hci_req_init(&req, hdev);
657
Johan Hedberg7d785252011-12-15 00:47:39 +0200658 hci_dev_lock(hdev);
659
Johan Hedberg890ea892013-03-15 17:06:52 -0500660 update_eir(&req);
661 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200662
663 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500664
665 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200666}
667
Johan Hedberg6a919082012-02-28 06:17:26 +0200668static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200669{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200670 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200671 return;
672
Johan Hedberg4f87da82012-03-02 19:55:56 +0200673 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200674
Johan Hedberg4f87da82012-03-02 19:55:56 +0200675 /* Non-mgmt controlled devices get this bit set
676 * implicitly so that pairing works for them, however
677 * for mgmt we require user-space to explicitly enable
678 * it
679 */
680 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200681}
682
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200683static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300684 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200685{
686 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200687
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200688 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300690 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200691
Johan Hedberg03811012010-12-08 00:21:06 +0200692 memset(&rp, 0, sizeof(rp));
693
Johan Hedberg03811012010-12-08 00:21:06 +0200694 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200695
696 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200697 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200698
699 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
700 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
701
702 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200703
704 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200705 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200706
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300707 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200708
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200709 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300710 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200711}
712
713static void mgmt_pending_free(struct pending_cmd *cmd)
714{
715 sock_put(cmd->sk);
716 kfree(cmd->param);
717 kfree(cmd);
718}
719
720static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300721 struct hci_dev *hdev, void *data,
722 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200723{
724 struct pending_cmd *cmd;
725
Andre Guedes12b94562012-06-07 19:05:45 -0300726 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200727 if (!cmd)
728 return NULL;
729
730 cmd->opcode = opcode;
731 cmd->index = hdev->id;
732
Andre Guedes12b94562012-06-07 19:05:45 -0300733 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200734 if (!cmd->param) {
735 kfree(cmd);
736 return NULL;
737 }
738
739 if (data)
740 memcpy(cmd->param, data, len);
741
742 cmd->sk = sk;
743 sock_hold(sk);
744
745 list_add(&cmd->list, &hdev->mgmt_pending);
746
747 return cmd;
748}
749
750static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300751 void (*cb)(struct pending_cmd *cmd,
752 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300753 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200754{
Andre Guedesa3d09352013-02-01 11:21:30 -0300755 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Andre Guedesa3d09352013-02-01 11:21:30 -0300757 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200758 if (opcode > 0 && cmd->opcode != opcode)
759 continue;
760
761 cb(cmd, data);
762 }
763}
764
765static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
766{
767 struct pending_cmd *cmd;
768
769 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
770 if (cmd->opcode == opcode)
771 return cmd;
772 }
773
774 return NULL;
775}
776
777static void mgmt_pending_remove(struct pending_cmd *cmd)
778{
779 list_del(&cmd->list);
780 mgmt_pending_free(cmd);
781}
782
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200783static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200784{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200785 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200786
Johan Hedbergaee9b212012-02-18 15:07:59 +0200787 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300788 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200789}
790
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200791static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300792 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200793{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300794 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200795 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200796 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200797
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200798 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200799
Johan Hedberga7e80f22013-01-09 16:05:19 +0200800 if (cp->val != 0x00 && cp->val != 0x01)
801 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
802 MGMT_STATUS_INVALID_PARAMS);
803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300804 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300806 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
807 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
808 MGMT_STATUS_BUSY);
809 goto failed;
810 }
811
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100812 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
813 cancel_delayed_work(&hdev->power_off);
814
815 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200816 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
817 data, len);
818 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100819 goto failed;
820 }
821 }
822
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200823 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200824 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200825 goto failed;
826 }
827
Johan Hedberg03811012010-12-08 00:21:06 +0200828 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
829 if (!cmd) {
830 err = -ENOMEM;
831 goto failed;
832 }
833
834 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200835 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200836 else
Johan Hedberg19202572013-01-14 22:33:51 +0200837 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200838
839 err = 0;
840
841failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300842 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200843 return err;
844}
845
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300846static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
847 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200848{
849 struct sk_buff *skb;
850 struct mgmt_hdr *hdr;
851
Andre Guedes790eff42012-06-07 19:05:46 -0300852 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200853 if (!skb)
854 return -ENOMEM;
855
856 hdr = (void *) skb_put(skb, sizeof(*hdr));
857 hdr->opcode = cpu_to_le16(event);
858 if (hdev)
859 hdr->index = cpu_to_le16(hdev->id);
860 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530861 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200862 hdr->len = cpu_to_le16(data_len);
863
864 if (data)
865 memcpy(skb_put(skb, data_len), data, data_len);
866
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100867 /* Time stamp */
868 __net_timestamp(skb);
869
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200870 hci_send_to_control(skb, skip_sk);
871 kfree_skb(skb);
872
873 return 0;
874}
875
876static int new_settings(struct hci_dev *hdev, struct sock *skip)
877{
878 __le32 ev;
879
880 ev = cpu_to_le32(get_current_settings(hdev));
881
882 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
883}
884
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300885struct cmd_lookup {
886 struct sock *sk;
887 struct hci_dev *hdev;
888 u8 mgmt_status;
889};
890
891static void settings_rsp(struct pending_cmd *cmd, void *data)
892{
893 struct cmd_lookup *match = data;
894
895 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
896
897 list_del(&cmd->list);
898
899 if (match->sk == NULL) {
900 match->sk = cmd->sk;
901 sock_hold(match->sk);
902 }
903
904 mgmt_pending_free(cmd);
905}
906
907static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
908{
909 u8 *status = data;
910
911 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
912 mgmt_pending_remove(cmd);
913}
914
Johan Hedberge6fe7982013-10-02 15:45:22 +0300915static u8 mgmt_bredr_support(struct hci_dev *hdev)
916{
917 if (!lmp_bredr_capable(hdev))
918 return MGMT_STATUS_NOT_SUPPORTED;
919 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
920 return MGMT_STATUS_REJECTED;
921 else
922 return MGMT_STATUS_SUCCESS;
923}
924
925static u8 mgmt_le_support(struct hci_dev *hdev)
926{
927 if (!lmp_le_capable(hdev))
928 return MGMT_STATUS_NOT_SUPPORTED;
929 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
930 return MGMT_STATUS_REJECTED;
931 else
932 return MGMT_STATUS_SUCCESS;
933}
934
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200935static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300936 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200937{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300938 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200939 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200940 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300941 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200942 int err;
943
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200944 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200945
Johan Hedberge6fe7982013-10-02 15:45:22 +0300946 status = mgmt_bredr_support(hdev);
947 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300948 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300949 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300950
Johan Hedberga7e80f22013-01-09 16:05:19 +0200951 if (cp->val != 0x00 && cp->val != 0x01)
952 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
953 MGMT_STATUS_INVALID_PARAMS);
954
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700955 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100956 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200957 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300958 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300960 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200961
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200963 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300964 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200965 goto failed;
966 }
967
968 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300969 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200970 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300971 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200972 goto failed;
973 }
974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200976 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300977 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200978 goto failed;
979 }
980
981 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200982 bool changed = false;
983
984 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
985 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
986 changed = true;
987 }
988
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200989 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200990 if (err < 0)
991 goto failed;
992
993 if (changed)
994 err = new_settings(hdev, sk);
995
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200996 goto failed;
997 }
998
999 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001000 if (hdev->discov_timeout > 0) {
1001 cancel_delayed_work(&hdev->discov_off);
1002 hdev->discov_timeout = 0;
1003 }
1004
1005 if (cp->val && timeout > 0) {
1006 hdev->discov_timeout = timeout;
1007 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1008 msecs_to_jiffies(hdev->discov_timeout * 1000));
1009 }
1010
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001011 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001012 goto failed;
1013 }
1014
1015 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1016 if (!cmd) {
1017 err = -ENOMEM;
1018 goto failed;
1019 }
1020
1021 scan = SCAN_PAGE;
1022
1023 if (cp->val)
1024 scan |= SCAN_INQUIRY;
1025 else
1026 cancel_delayed_work(&hdev->discov_off);
1027
1028 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1029 if (err < 0)
1030 mgmt_pending_remove(cmd);
1031
Johan Hedberg03811012010-12-08 00:21:06 +02001032 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001033 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001034
1035failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001036 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001037 return err;
1038}
1039
Johan Hedberg406d7802013-03-15 17:07:09 -05001040static void write_fast_connectable(struct hci_request *req, bool enable)
1041{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001042 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001043 struct hci_cp_write_page_scan_activity acp;
1044 u8 type;
1045
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001046 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1047 return;
1048
Johan Hedberg406d7802013-03-15 17:07:09 -05001049 if (enable) {
1050 type = PAGE_SCAN_TYPE_INTERLACED;
1051
1052 /* 160 msec page scan interval */
1053 acp.interval = __constant_cpu_to_le16(0x0100);
1054 } else {
1055 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1056
1057 /* default 1.28 sec page scan */
1058 acp.interval = __constant_cpu_to_le16(0x0800);
1059 }
1060
1061 acp.window = __constant_cpu_to_le16(0x0012);
1062
Johan Hedbergbd98b992013-03-15 17:07:13 -05001063 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1064 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1065 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1066 sizeof(acp), &acp);
1067
1068 if (hdev->page_scan_type != type)
1069 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001070}
1071
Johan Hedberg2b76f452013-03-15 17:07:04 -05001072static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1073{
1074 struct pending_cmd *cmd;
1075
1076 BT_DBG("status 0x%02x", status);
1077
1078 hci_dev_lock(hdev);
1079
1080 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1081 if (!cmd)
1082 goto unlock;
1083
1084 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1085
1086 mgmt_pending_remove(cmd);
1087
1088unlock:
1089 hci_dev_unlock(hdev);
1090}
1091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001092static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001093 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001094{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001095 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001096 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001097 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001098 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001099 int err;
1100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001101 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001102
Johan Hedberge6fe7982013-10-02 15:45:22 +03001103 status = mgmt_bredr_support(hdev);
1104 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001105 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001106 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001107
Johan Hedberga7e80f22013-01-09 16:05:19 +02001108 if (cp->val != 0x00 && cp->val != 0x01)
1109 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1110 MGMT_STATUS_INVALID_PARAMS);
1111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001112 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001113
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001114 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001115 bool changed = false;
1116
1117 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1118 changed = true;
1119
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001120 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001121 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001122 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001123 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1124 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1125 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001126
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001127 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001128 if (err < 0)
1129 goto failed;
1130
1131 if (changed)
1132 err = new_settings(hdev, sk);
1133
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001134 goto failed;
1135 }
1136
1137 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001138 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001139 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001140 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001141 goto failed;
1142 }
1143
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001144 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001145 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001146 goto failed;
1147 }
1148
1149 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1150 if (!cmd) {
1151 err = -ENOMEM;
1152 goto failed;
1153 }
1154
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001155 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001156 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001157 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001158 scan = 0;
1159
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001160 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001161 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001162 cancel_delayed_work(&hdev->discov_off);
1163 }
1164
Johan Hedberg2b76f452013-03-15 17:07:04 -05001165 hci_req_init(&req, hdev);
1166
1167 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1168
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001169 /* If we're going from non-connectable to connectable or
1170 * vice-versa when fast connectable is enabled ensure that fast
1171 * connectable gets disabled. write_fast_connectable won't do
1172 * anything if the page scan parameters are already what they
1173 * should be.
1174 */
1175 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001176 write_fast_connectable(&req, false);
1177
Johan Hedberg2b76f452013-03-15 17:07:04 -05001178 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001179 if (err < 0)
1180 mgmt_pending_remove(cmd);
1181
1182failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001183 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001184 return err;
1185}
1186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001188 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001189{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001190 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001191 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001192 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001194 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001195
Johan Hedberga7e80f22013-01-09 16:05:19 +02001196 if (cp->val != 0x00 && cp->val != 0x01)
1197 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1198 MGMT_STATUS_INVALID_PARAMS);
1199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001200 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001201
1202 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001203 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001204 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001205 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001206
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001207 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001208 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001209 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001210
Marcel Holtmann55594352013-10-06 16:11:57 -07001211 if (changed)
1212 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Marcel Holtmann55594352013-10-06 16:11:57 -07001214unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001215 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001216 return err;
1217}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001218
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001219static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1220 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001221{
1222 struct mgmt_mode *cp = data;
1223 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001224 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001225 int err;
1226
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001227 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001228
Johan Hedberge6fe7982013-10-02 15:45:22 +03001229 status = mgmt_bredr_support(hdev);
1230 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001231 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001232 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001233
Johan Hedberga7e80f22013-01-09 16:05:19 +02001234 if (cp->val != 0x00 && cp->val != 0x01)
1235 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1236 MGMT_STATUS_INVALID_PARAMS);
1237
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001238 hci_dev_lock(hdev);
1239
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001240 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001241 bool changed = false;
1242
1243 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001244 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001245 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1246 changed = true;
1247 }
1248
1249 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1250 if (err < 0)
1251 goto failed;
1252
1253 if (changed)
1254 err = new_settings(hdev, sk);
1255
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001256 goto failed;
1257 }
1258
1259 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001260 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001261 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001262 goto failed;
1263 }
1264
1265 val = !!cp->val;
1266
1267 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1268 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1269 goto failed;
1270 }
1271
1272 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1273 if (!cmd) {
1274 err = -ENOMEM;
1275 goto failed;
1276 }
1277
1278 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1279 if (err < 0) {
1280 mgmt_pending_remove(cmd);
1281 goto failed;
1282 }
1283
1284failed:
1285 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001286 return err;
1287}
1288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001289static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001290{
1291 struct mgmt_mode *cp = data;
1292 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001293 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001294 int err;
1295
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001296 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001297
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001298 status = mgmt_bredr_support(hdev);
1299 if (status)
1300 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1301
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001302 if (!lmp_ssp_capable(hdev))
1303 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1304 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001305
Johan Hedberga7e80f22013-01-09 16:05:19 +02001306 if (cp->val != 0x00 && cp->val != 0x01)
1307 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1308 MGMT_STATUS_INVALID_PARAMS);
1309
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001310 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001311
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001312 if (!hdev_is_powered(hdev)) {
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 Padovan6039aa72012-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 Hedbergaee9b212012-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
3258static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3259{
3260 struct mgmt_mode *cp = data;
3261 struct pending_cmd *cmd;
3262 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003263 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003264 int err;
3265
3266 BT_DBG("request for %s", hdev->name);
3267
Johan Hedberge6fe7982013-10-02 15:45:22 +03003268 status = mgmt_le_support(hdev);
3269 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003270 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003271 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003272
3273 if (cp->val != 0x00 && cp->val != 0x01)
3274 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3275 MGMT_STATUS_INVALID_PARAMS);
3276
3277 hci_dev_lock(hdev);
3278
3279 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003280 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003281
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003282 /* The following conditions are ones which mean that we should
3283 * not do any HCI communication but directly send a mgmt
3284 * response to user space (after toggling the flag if
3285 * necessary).
3286 */
3287 if (!hdev_is_powered(hdev) || val == enabled ||
3288 hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECTED)) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003289 bool changed = false;
3290
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003291 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3292 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003293 changed = true;
3294 }
3295
3296 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3297 if (err < 0)
3298 goto unlock;
3299
3300 if (changed)
3301 err = new_settings(hdev, sk);
3302
3303 goto unlock;
3304 }
3305
3306 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3307 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3308 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3309 MGMT_STATUS_BUSY);
3310 goto unlock;
3311 }
3312
3313 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3314 if (!cmd) {
3315 err = -ENOMEM;
3316 goto unlock;
3317 }
3318
3319 hci_req_init(&req, hdev);
3320
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003321 if (val)
3322 enable_advertising(&req);
3323 else
3324 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003325
3326 err = hci_req_run(&req, set_advertising_complete);
3327 if (err < 0)
3328 mgmt_pending_remove(cmd);
3329
3330unlock:
3331 hci_dev_unlock(hdev);
3332 return err;
3333}
3334
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003335static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3336 void *data, u16 len)
3337{
3338 struct mgmt_cp_set_static_address *cp = data;
3339 int err;
3340
3341 BT_DBG("%s", hdev->name);
3342
Marcel Holtmann62af4442013-10-02 22:10:32 -07003343 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003344 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003345 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003346
3347 if (hdev_is_powered(hdev))
3348 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3349 MGMT_STATUS_REJECTED);
3350
3351 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3352 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3353 return cmd_status(sk, hdev->id,
3354 MGMT_OP_SET_STATIC_ADDRESS,
3355 MGMT_STATUS_INVALID_PARAMS);
3356
3357 /* Two most significant bits shall be set */
3358 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3359 return cmd_status(sk, hdev->id,
3360 MGMT_OP_SET_STATIC_ADDRESS,
3361 MGMT_STATUS_INVALID_PARAMS);
3362 }
3363
3364 hci_dev_lock(hdev);
3365
3366 bacpy(&hdev->static_addr, &cp->bdaddr);
3367
3368 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3369
3370 hci_dev_unlock(hdev);
3371
3372 return err;
3373}
3374
Johan Hedberg33e38b32013-03-15 17:07:05 -05003375static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3376{
3377 struct pending_cmd *cmd;
3378
3379 BT_DBG("status 0x%02x", status);
3380
3381 hci_dev_lock(hdev);
3382
3383 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3384 if (!cmd)
3385 goto unlock;
3386
3387 if (status) {
3388 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3389 mgmt_status(status));
3390 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003391 struct mgmt_mode *cp = cmd->param;
3392
3393 if (cp->val)
3394 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3395 else
3396 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3397
Johan Hedberg33e38b32013-03-15 17:07:05 -05003398 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3399 new_settings(hdev, cmd->sk);
3400 }
3401
3402 mgmt_pending_remove(cmd);
3403
3404unlock:
3405 hci_dev_unlock(hdev);
3406}
3407
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003408static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003409 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003410{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003411 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003412 struct pending_cmd *cmd;
3413 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003414 int err;
3415
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003416 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003417
Johan Hedberg56f87902013-10-02 13:43:13 +03003418 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3419 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003420 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3421 MGMT_STATUS_NOT_SUPPORTED);
3422
Johan Hedberga7e80f22013-01-09 16:05:19 +02003423 if (cp->val != 0x00 && cp->val != 0x01)
3424 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3425 MGMT_STATUS_INVALID_PARAMS);
3426
Johan Hedberg5400c042012-02-21 16:40:33 +02003427 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003428 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003429 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003430
3431 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003432 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003433 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003434
3435 hci_dev_lock(hdev);
3436
Johan Hedberg05cbf292013-03-15 17:07:07 -05003437 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3438 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3439 MGMT_STATUS_BUSY);
3440 goto unlock;
3441 }
3442
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003443 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3444 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3445 hdev);
3446 goto unlock;
3447 }
3448
Johan Hedberg33e38b32013-03-15 17:07:05 -05003449 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3450 data, len);
3451 if (!cmd) {
3452 err = -ENOMEM;
3453 goto unlock;
3454 }
3455
3456 hci_req_init(&req, hdev);
3457
Johan Hedberg406d7802013-03-15 17:07:09 -05003458 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003459
3460 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003461 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003462 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003463 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003464 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003465 }
3466
Johan Hedberg33e38b32013-03-15 17:07:05 -05003467unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003468 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003469
Antti Julkuf6422ec2011-06-22 13:11:56 +03003470 return err;
3471}
3472
Johan Hedberg0663ca22013-10-02 13:43:14 +03003473static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3474{
3475 struct pending_cmd *cmd;
3476
3477 BT_DBG("status 0x%02x", status);
3478
3479 hci_dev_lock(hdev);
3480
3481 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3482 if (!cmd)
3483 goto unlock;
3484
3485 if (status) {
3486 u8 mgmt_err = mgmt_status(status);
3487
3488 /* We need to restore the flag if related HCI commands
3489 * failed.
3490 */
3491 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3492
3493 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3494 } else {
3495 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3496 new_settings(hdev, cmd->sk);
3497 }
3498
3499 mgmt_pending_remove(cmd);
3500
3501unlock:
3502 hci_dev_unlock(hdev);
3503}
3504
3505static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3506{
3507 struct mgmt_mode *cp = data;
3508 struct pending_cmd *cmd;
3509 struct hci_request req;
3510 int err;
3511
3512 BT_DBG("request for %s", hdev->name);
3513
3514 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3515 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3516 MGMT_STATUS_NOT_SUPPORTED);
3517
3518 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3519 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3520 MGMT_STATUS_REJECTED);
3521
3522 if (cp->val != 0x00 && cp->val != 0x01)
3523 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3524 MGMT_STATUS_INVALID_PARAMS);
3525
3526 hci_dev_lock(hdev);
3527
3528 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3529 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3530 goto unlock;
3531 }
3532
3533 if (!hdev_is_powered(hdev)) {
3534 if (!cp->val) {
3535 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3536 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3537 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3538 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3539 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3540 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3541 }
3542
3543 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3544
3545 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3546 if (err < 0)
3547 goto unlock;
3548
3549 err = new_settings(hdev, sk);
3550 goto unlock;
3551 }
3552
3553 /* Reject disabling when powered on */
3554 if (!cp->val) {
3555 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3556 MGMT_STATUS_REJECTED);
3557 goto unlock;
3558 }
3559
3560 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3561 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3562 MGMT_STATUS_BUSY);
3563 goto unlock;
3564 }
3565
3566 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3567 if (!cmd) {
3568 err = -ENOMEM;
3569 goto unlock;
3570 }
3571
3572 /* We need to flip the bit already here so that hci_update_ad
3573 * generates the correct flags.
3574 */
3575 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3576
3577 hci_req_init(&req, hdev);
3578 hci_update_ad(&req);
3579 err = hci_req_run(&req, set_bredr_complete);
3580 if (err < 0)
3581 mgmt_pending_remove(cmd);
3582
3583unlock:
3584 hci_dev_unlock(hdev);
3585 return err;
3586}
3587
Johan Hedberg3f706b72013-01-20 14:27:16 +02003588static bool ltk_is_valid(struct mgmt_ltk_info *key)
3589{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003590 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3591 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003592 if (key->master != 0x00 && key->master != 0x01)
3593 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003594 if (!bdaddr_type_is_le(key->addr.type))
3595 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003596 return true;
3597}
3598
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003599static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003600 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003601{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003602 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3603 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003604 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003605
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003606 BT_DBG("request for %s", hdev->name);
3607
3608 if (!lmp_le_capable(hdev))
3609 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3610 MGMT_STATUS_NOT_SUPPORTED);
3611
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003612 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003613
3614 expected_len = sizeof(*cp) + key_count *
3615 sizeof(struct mgmt_ltk_info);
3616 if (expected_len != len) {
3617 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003618 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003619 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003620 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003621 }
3622
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003623 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003624
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003625 for (i = 0; i < key_count; i++) {
3626 struct mgmt_ltk_info *key = &cp->keys[i];
3627
Johan Hedberg3f706b72013-01-20 14:27:16 +02003628 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003629 return cmd_status(sk, hdev->id,
3630 MGMT_OP_LOAD_LONG_TERM_KEYS,
3631 MGMT_STATUS_INVALID_PARAMS);
3632 }
3633
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003634 hci_dev_lock(hdev);
3635
3636 hci_smp_ltks_clear(hdev);
3637
3638 for (i = 0; i < key_count; i++) {
3639 struct mgmt_ltk_info *key = &cp->keys[i];
3640 u8 type;
3641
3642 if (key->master)
3643 type = HCI_SMP_LTK;
3644 else
3645 type = HCI_SMP_LTK_SLAVE;
3646
Hemant Gupta4596fde2012-04-16 14:57:40 +05303647 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003648 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003649 type, 0, key->authenticated, key->val,
3650 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003651 }
3652
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003653 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3654 NULL, 0);
3655
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003656 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003657
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003658 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003659}
3660
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003661static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003662 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3663 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003664 bool var_len;
3665 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003666} mgmt_handlers[] = {
3667 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003668 { read_version, false, MGMT_READ_VERSION_SIZE },
3669 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3670 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3671 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3672 { set_powered, false, MGMT_SETTING_SIZE },
3673 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3674 { set_connectable, false, MGMT_SETTING_SIZE },
3675 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3676 { set_pairable, false, MGMT_SETTING_SIZE },
3677 { set_link_security, false, MGMT_SETTING_SIZE },
3678 { set_ssp, false, MGMT_SETTING_SIZE },
3679 { set_hs, false, MGMT_SETTING_SIZE },
3680 { set_le, false, MGMT_SETTING_SIZE },
3681 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3682 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3683 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3684 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3685 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3686 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3687 { disconnect, false, MGMT_DISCONNECT_SIZE },
3688 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3689 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3690 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3691 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3692 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3693 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3694 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3695 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3696 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3697 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3698 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3699 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3700 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3701 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3702 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3703 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3704 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3705 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3706 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003707 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003708 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003709 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003710 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003711};
3712
3713
Johan Hedberg03811012010-12-08 00:21:06 +02003714int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3715{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003716 void *buf;
3717 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003718 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003719 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003720 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003721 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003722 int err;
3723
3724 BT_DBG("got %zu bytes", msglen);
3725
3726 if (msglen < sizeof(*hdr))
3727 return -EINVAL;
3728
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003729 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003730 if (!buf)
3731 return -ENOMEM;
3732
3733 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3734 err = -EFAULT;
3735 goto done;
3736 }
3737
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003738 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003739 opcode = __le16_to_cpu(hdr->opcode);
3740 index = __le16_to_cpu(hdr->index);
3741 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003742
3743 if (len != msglen - sizeof(*hdr)) {
3744 err = -EINVAL;
3745 goto done;
3746 }
3747
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003748 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003749 hdev = hci_dev_get(index);
3750 if (!hdev) {
3751 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003752 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003753 goto done;
3754 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003755
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003756 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3757 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003758 err = cmd_status(sk, index, opcode,
3759 MGMT_STATUS_INVALID_INDEX);
3760 goto done;
3761 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003762 }
3763
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003764 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003765 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003766 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003767 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003768 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003769 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003770 }
3771
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003772 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003773 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003774 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003775 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003776 goto done;
3777 }
3778
Johan Hedbergbe22b542012-03-01 22:24:41 +02003779 handler = &mgmt_handlers[opcode];
3780
3781 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003782 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003783 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003784 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003785 goto done;
3786 }
3787
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003788 if (hdev)
3789 mgmt_init_hdev(sk, hdev);
3790
3791 cp = buf + sizeof(*hdr);
3792
Johan Hedbergbe22b542012-03-01 22:24:41 +02003793 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003794 if (err < 0)
3795 goto done;
3796
Johan Hedberg03811012010-12-08 00:21:06 +02003797 err = msglen;
3798
3799done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003800 if (hdev)
3801 hci_dev_put(hdev);
3802
Johan Hedberg03811012010-12-08 00:21:06 +02003803 kfree(buf);
3804 return err;
3805}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003806
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003807void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003808{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003809 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003810 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003811
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003812 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003813}
3814
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003815void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003816{
Johan Hedberg5f159032012-03-02 03:13:19 +02003817 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003818
Marcel Holtmann1514b892013-10-06 08:25:01 -07003819 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003820 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003821
Johan Hedberg744cf192011-11-08 20:40:14 +02003822 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003823
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003824 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003825}
3826
Johan Hedberg890ea892013-03-15 17:06:52 -05003827static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003828{
Johan Hedberg890ea892013-03-15 17:06:52 -05003829 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003830 u8 scan = 0;
3831
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003832 /* Ensure that fast connectable is disabled. This function will
3833 * not do anything if the page scan parameters are already what
3834 * they should be.
3835 */
3836 write_fast_connectable(req, false);
3837
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003838 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3839 scan |= SCAN_PAGE;
3840 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3841 scan |= SCAN_INQUIRY;
3842
Johan Hedberg890ea892013-03-15 17:06:52 -05003843 if (scan)
3844 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003845}
3846
Johan Hedberg229ab392013-03-15 17:06:53 -05003847static void powered_complete(struct hci_dev *hdev, u8 status)
3848{
3849 struct cmd_lookup match = { NULL, hdev };
3850
3851 BT_DBG("status 0x%02x", status);
3852
3853 hci_dev_lock(hdev);
3854
3855 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3856
3857 new_settings(hdev, match.sk);
3858
3859 hci_dev_unlock(hdev);
3860
3861 if (match.sk)
3862 sock_put(match.sk);
3863}
3864
Johan Hedberg70da6242013-03-15 17:06:51 -05003865static int powered_update_hci(struct hci_dev *hdev)
3866{
Johan Hedberg890ea892013-03-15 17:06:52 -05003867 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003868 u8 link_sec;
3869
Johan Hedberg890ea892013-03-15 17:06:52 -05003870 hci_req_init(&req, hdev);
3871
Johan Hedberg70da6242013-03-15 17:06:51 -05003872 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3873 !lmp_host_ssp_capable(hdev)) {
3874 u8 ssp = 1;
3875
Johan Hedberg890ea892013-03-15 17:06:52 -05003876 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003877 }
3878
Johan Hedbergc73eee92013-04-19 18:35:21 +03003879 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3880 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003881 struct hci_cp_write_le_host_supported cp;
3882
3883 cp.le = 1;
3884 cp.simul = lmp_le_br_capable(hdev);
3885
3886 /* Check first if we already have the right
3887 * host state (host features set)
3888 */
3889 if (cp.le != lmp_host_le_capable(hdev) ||
3890 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003891 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3892 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003893
3894 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3895 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003896 }
3897
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003898 if (lmp_le_capable(hdev)) {
3899 /* Set random address to static address if configured */
3900 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3901 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3902 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003903
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003904 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3905 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003906 }
3907
Johan Hedberg70da6242013-03-15 17:06:51 -05003908 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3909 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003910 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3911 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003912
3913 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003914 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3915 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003916 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003917 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003918 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003919 }
3920
Johan Hedberg229ab392013-03-15 17:06:53 -05003921 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003922}
3923
Johan Hedberg744cf192011-11-08 20:40:14 +02003924int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003925{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003926 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003927 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3928 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003929 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003930
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003931 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3932 return 0;
3933
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003934 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003935 if (powered_update_hci(hdev) == 0)
3936 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003937
Johan Hedberg229ab392013-03-15 17:06:53 -05003938 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3939 &match);
3940 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003941 }
3942
Johan Hedberg229ab392013-03-15 17:06:53 -05003943 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3944 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3945
3946 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3947 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3948 zero_cod, sizeof(zero_cod), NULL);
3949
3950new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003951 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003952
3953 if (match.sk)
3954 sock_put(match.sk);
3955
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003956 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003957}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003958
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003959void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03003960{
3961 struct pending_cmd *cmd;
3962 u8 status;
3963
3964 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3965 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003966 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03003967
3968 if (err == -ERFKILL)
3969 status = MGMT_STATUS_RFKILLED;
3970 else
3971 status = MGMT_STATUS_FAILED;
3972
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003973 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03003974
3975 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03003976}
3977
Johan Hedberg744cf192011-11-08 20:40:14 +02003978int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003979{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003980 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003981 bool changed = false;
3982 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003983
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003984 if (discoverable) {
3985 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3986 changed = true;
3987 } else {
3988 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3989 changed = true;
3990 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003991
Johan Hedberged9b5f22012-02-21 20:47:06 +02003992 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003993 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003994
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003995 if (changed)
3996 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003997
Johan Hedberg73f22f62010-12-29 16:00:25 +02003998 if (match.sk)
3999 sock_put(match.sk);
4000
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004001 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004002}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004003
Johan Hedberg744cf192011-11-08 20:40:14 +02004004int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004005{
Johan Hedberg2b76f452013-03-15 17:07:04 -05004006 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004007 bool changed = false;
4008 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004009
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004010 if (connectable) {
4011 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4012 changed = true;
4013 } else {
4014 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4015 changed = true;
4016 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004017
Johan Hedberg2b76f452013-03-15 17:07:04 -05004018 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004019
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004020 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004021 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004022
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004023 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004024}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004025
Johan Hedberg744cf192011-11-08 20:40:14 +02004026int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004027{
Johan Hedbergca69b792011-11-11 18:10:00 +02004028 u8 mgmt_err = mgmt_status(status);
4029
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004030 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004031 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004032 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004033
4034 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004035 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004036 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004037
4038 return 0;
4039}
4040
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004041int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4042 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004043{
Johan Hedberg86742e12011-11-07 23:13:38 +02004044 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004045
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004046 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004047
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004048 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004049 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004050 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004051 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004052 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004053 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004054
Johan Hedberg744cf192011-11-08 20:40:14 +02004055 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004056}
Johan Hedbergf7520542011-01-20 12:34:39 +02004057
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004058int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4059{
4060 struct mgmt_ev_new_long_term_key ev;
4061
4062 memset(&ev, 0, sizeof(ev));
4063
4064 ev.store_hint = persistent;
4065 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004066 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004067 ev.key.authenticated = key->authenticated;
4068 ev.key.enc_size = key->enc_size;
4069 ev.key.ediv = key->ediv;
4070
4071 if (key->type == HCI_SMP_LTK)
4072 ev.key.master = 1;
4073
4074 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4075 memcpy(ev.key.val, key->val, sizeof(key->val));
4076
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004077 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4078 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004079}
4080
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004081void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4082 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4083 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004084{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004085 char buf[512];
4086 struct mgmt_ev_device_connected *ev = (void *) buf;
4087 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004088
Johan Hedbergb644ba32012-01-17 21:48:47 +02004089 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004090 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004091
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004092 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004093
Johan Hedbergb644ba32012-01-17 21:48:47 +02004094 if (name_len > 0)
4095 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004096 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004097
4098 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004099 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004100 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004101
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004102 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004103
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004104 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4105 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004106}
4107
Johan Hedberg8962ee72011-01-20 12:40:27 +02004108static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4109{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004110 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004111 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004112 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004113
Johan Hedberg88c3df12012-02-09 14:27:38 +02004114 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4115 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004116
Johan Hedbergaee9b212012-02-18 15:07:59 +02004117 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004118 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004119
4120 *sk = cmd->sk;
4121 sock_hold(*sk);
4122
Johan Hedberga664b5b2011-02-19 12:06:02 -03004123 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004124}
4125
Johan Hedberg124f6e32012-02-09 13:50:12 +02004126static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004127{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004128 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004129 struct mgmt_cp_unpair_device *cp = cmd->param;
4130 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004131
4132 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004133 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4134 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004135
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004136 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4137
Johan Hedbergaee9b212012-02-18 15:07:59 +02004138 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004139
4140 mgmt_pending_remove(cmd);
4141}
4142
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004143void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4144 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004145{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004146 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004147 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004148
Johan Hedberg744cf192011-11-08 20:40:14 +02004149 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004150
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004151 bacpy(&ev.addr.bdaddr, bdaddr);
4152 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4153 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004154
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004155 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004156
4157 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004158 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004159
Johan Hedberg124f6e32012-02-09 13:50:12 +02004160 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004161 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004162}
4163
Marcel Holtmann78929242013-10-06 23:55:47 -07004164void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4165 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004166{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004167 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004168 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004169
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004170 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4171 hdev);
4172
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004173 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004174 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004175 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004176
Johan Hedberg88c3df12012-02-09 14:27:38 +02004177 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004178 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004179
Marcel Holtmann78929242013-10-06 23:55:47 -07004180 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4181 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004182
Johan Hedberga664b5b2011-02-19 12:06:02 -03004183 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004184}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004185
Marcel Holtmann445608d2013-10-06 23:55:48 -07004186void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4187 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004188{
4189 struct mgmt_ev_connect_failed ev;
4190
Johan Hedberg4c659c32011-11-07 23:13:39 +02004191 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004192 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004193 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004194
Marcel Holtmann445608d2013-10-06 23:55:48 -07004195 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004196}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004197
Johan Hedberg744cf192011-11-08 20:40:14 +02004198int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004199{
4200 struct mgmt_ev_pin_code_request ev;
4201
Johan Hedbergd8457692012-02-17 14:24:57 +02004202 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004203 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004204 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004205
Johan Hedberg744cf192011-11-08 20:40:14 +02004206 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004207 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004208}
4209
Johan Hedberg744cf192011-11-08 20:40:14 +02004210int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004211 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004212{
4213 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004214 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004215 int err;
4216
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004217 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004218 if (!cmd)
4219 return -ENOENT;
4220
Johan Hedbergd8457692012-02-17 14:24:57 +02004221 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004222 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004223
Johan Hedbergaee9b212012-02-18 15:07:59 +02004224 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004225 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004226
Johan Hedberga664b5b2011-02-19 12:06:02 -03004227 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004228
4229 return err;
4230}
4231
Johan Hedberg744cf192011-11-08 20:40:14 +02004232int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004233 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004234{
4235 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004236 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004237 int err;
4238
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004239 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004240 if (!cmd)
4241 return -ENOENT;
4242
Johan Hedbergd8457692012-02-17 14:24:57 +02004243 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004244 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004245
Johan Hedbergaee9b212012-02-18 15:07:59 +02004246 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004247 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004248
Johan Hedberga664b5b2011-02-19 12:06:02 -03004249 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004250
4251 return err;
4252}
Johan Hedberga5c29682011-02-19 12:05:57 -03004253
Johan Hedberg744cf192011-11-08 20:40:14 +02004254int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004255 u8 link_type, u8 addr_type, __le32 value,
4256 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004257{
4258 struct mgmt_ev_user_confirm_request ev;
4259
Johan Hedberg744cf192011-11-08 20:40:14 +02004260 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004261
Johan Hedberg272d90d2012-02-09 15:26:12 +02004262 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004263 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004264 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004265 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004266
Johan Hedberg744cf192011-11-08 20:40:14 +02004267 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004268 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004269}
4270
Johan Hedberg272d90d2012-02-09 15:26:12 +02004271int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004272 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004273{
4274 struct mgmt_ev_user_passkey_request ev;
4275
4276 BT_DBG("%s", hdev->name);
4277
Johan Hedberg272d90d2012-02-09 15:26:12 +02004278 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004279 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004280
4281 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004282 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004283}
4284
Brian Gix0df4c182011-11-16 13:53:13 -08004285static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004286 u8 link_type, u8 addr_type, u8 status,
4287 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004288{
4289 struct pending_cmd *cmd;
4290 struct mgmt_rp_user_confirm_reply rp;
4291 int err;
4292
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004293 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004294 if (!cmd)
4295 return -ENOENT;
4296
Johan Hedberg272d90d2012-02-09 15:26:12 +02004297 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004298 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004299 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004300 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004301
Johan Hedberga664b5b2011-02-19 12:06:02 -03004302 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004303
4304 return err;
4305}
4306
Johan Hedberg744cf192011-11-08 20:40:14 +02004307int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004308 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004309{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004310 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004311 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004312}
4313
Johan Hedberg272d90d2012-02-09 15:26:12 +02004314int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004315 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004316{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004317 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004318 status,
4319 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004320}
Johan Hedberg2a611692011-02-19 12:06:00 -03004321
Brian Gix604086b2011-11-23 08:28:33 -08004322int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004323 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004324{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004325 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004326 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004327}
4328
Johan Hedberg272d90d2012-02-09 15:26:12 +02004329int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004330 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004331{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004332 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004333 status,
4334 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004335}
4336
Johan Hedberg92a25252012-09-06 18:39:26 +03004337int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4338 u8 link_type, u8 addr_type, u32 passkey,
4339 u8 entered)
4340{
4341 struct mgmt_ev_passkey_notify ev;
4342
4343 BT_DBG("%s", hdev->name);
4344
4345 bacpy(&ev.addr.bdaddr, bdaddr);
4346 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4347 ev.passkey = __cpu_to_le32(passkey);
4348 ev.entered = entered;
4349
4350 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4351}
4352
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004353int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004354 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004355{
4356 struct mgmt_ev_auth_failed ev;
4357
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004358 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004359 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004360 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004361
Johan Hedberg744cf192011-11-08 20:40:14 +02004362 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004363}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004364
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004365int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4366{
4367 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004368 bool changed = false;
4369 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004370
4371 if (status) {
4372 u8 mgmt_err = mgmt_status(status);
4373 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004374 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004375 return 0;
4376 }
4377
Johan Hedberg47990ea2012-02-22 11:58:37 +02004378 if (test_bit(HCI_AUTH, &hdev->flags)) {
4379 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4380 changed = true;
4381 } else {
4382 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4383 changed = true;
4384 }
4385
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004386 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004387 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004388
Johan Hedberg47990ea2012-02-22 11:58:37 +02004389 if (changed)
4390 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004391
4392 if (match.sk)
4393 sock_put(match.sk);
4394
4395 return err;
4396}
4397
Johan Hedberg890ea892013-03-15 17:06:52 -05004398static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004399{
Johan Hedberg890ea892013-03-15 17:06:52 -05004400 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004401 struct hci_cp_write_eir cp;
4402
Johan Hedberg976eb202012-10-24 21:12:01 +03004403 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004404 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004405
Johan Hedbergc80da272012-02-22 15:38:48 +02004406 memset(hdev->eir, 0, sizeof(hdev->eir));
4407
Johan Hedbergcacaf522012-02-21 00:52:42 +02004408 memset(&cp, 0, sizeof(cp));
4409
Johan Hedberg890ea892013-03-15 17:06:52 -05004410 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004411}
4412
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004413int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004414{
4415 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004416 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004417 bool changed = false;
4418 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004419
4420 if (status) {
4421 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004422
4423 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004424 &hdev->dev_flags)) {
4425 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004426 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004427 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004428
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004429 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4430 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004431
4432 return err;
4433 }
4434
4435 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004436 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004437 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004438 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4439 if (!changed)
4440 changed = test_and_clear_bit(HCI_HS_ENABLED,
4441 &hdev->dev_flags);
4442 else
4443 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004444 }
4445
4446 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4447
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004448 if (changed)
4449 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004450
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004451 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004452 sock_put(match.sk);
4453
Johan Hedberg890ea892013-03-15 17:06:52 -05004454 hci_req_init(&req, hdev);
4455
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004456 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004457 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004458 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004459 clear_eir(&req);
4460
4461 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004462
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004463 return err;
4464}
4465
Johan Hedberg92da6092013-03-15 17:06:55 -05004466static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004467{
4468 struct cmd_lookup *match = data;
4469
Johan Hedberg90e70452012-02-23 23:09:40 +02004470 if (match->sk == NULL) {
4471 match->sk = cmd->sk;
4472 sock_hold(match->sk);
4473 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004474}
4475
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004476int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004477 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004478{
Johan Hedberg90e70452012-02-23 23:09:40 +02004479 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4480 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004481
Johan Hedberg92da6092013-03-15 17:06:55 -05004482 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4483 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4484 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004485
4486 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004487 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4488 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004489
4490 if (match.sk)
4491 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004492
4493 return err;
4494}
4495
Johan Hedberg744cf192011-11-08 20:40:14 +02004496int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004497{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004498 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004499 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004500
Johan Hedberg13928972013-03-15 17:07:00 -05004501 if (status)
4502 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004503
4504 memset(&ev, 0, sizeof(ev));
4505 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004506 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004507
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004508 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004509 if (!cmd) {
4510 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004511
Johan Hedberg13928972013-03-15 17:07:00 -05004512 /* If this is a HCI command related to powering on the
4513 * HCI dev don't send any mgmt signals.
4514 */
4515 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4516 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004517 }
4518
Johan Hedberg13928972013-03-15 17:07:00 -05004519 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4520 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004521}
Szymon Jancc35938b2011-03-22 13:12:21 +01004522
Johan Hedberg744cf192011-11-08 20:40:14 +02004523int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004524 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004525{
4526 struct pending_cmd *cmd;
4527 int err;
4528
Johan Hedberg744cf192011-11-08 20:40:14 +02004529 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004530
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004531 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004532 if (!cmd)
4533 return -ENOENT;
4534
4535 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004536 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4537 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004538 } else {
4539 struct mgmt_rp_read_local_oob_data rp;
4540
4541 memcpy(rp.hash, hash, sizeof(rp.hash));
4542 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4543
Johan Hedberg744cf192011-11-08 20:40:14 +02004544 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004545 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4546 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004547 }
4548
4549 mgmt_pending_remove(cmd);
4550
4551 return err;
4552}
Johan Hedberge17acd42011-03-30 23:57:16 +03004553
Marcel Holtmann901801b2013-10-06 23:55:51 -07004554void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4555 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4556 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004557{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004558 char buf[512];
4559 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004560 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004561
Andre Guedes12602d02013-04-30 15:29:40 -03004562 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004563 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004564
Johan Hedberg1dc06092012-01-15 21:01:23 +02004565 /* Leave 5 bytes for a potential CoD field */
4566 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004567 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004568
Johan Hedberg1dc06092012-01-15 21:01:23 +02004569 memset(buf, 0, sizeof(buf));
4570
Johan Hedberge319d2e2012-01-15 19:51:59 +02004571 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004572 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004573 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004574 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304575 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004576 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304577 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004578
Johan Hedberg1dc06092012-01-15 21:01:23 +02004579 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004580 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004581
Johan Hedberg1dc06092012-01-15 21:01:23 +02004582 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4583 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004584 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004585
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004586 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004587 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004588
Marcel Holtmann901801b2013-10-06 23:55:51 -07004589 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004590}
Johan Hedberga88a9652011-03-30 13:18:12 +03004591
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004592void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4593 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004594{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004595 struct mgmt_ev_device_found *ev;
4596 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4597 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004598
Johan Hedbergb644ba32012-01-17 21:48:47 +02004599 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004600
Johan Hedbergb644ba32012-01-17 21:48:47 +02004601 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004602
Johan Hedbergb644ba32012-01-17 21:48:47 +02004603 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004604 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004605 ev->rssi = rssi;
4606
4607 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004608 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004609
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004610 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004611
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004612 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004613}
Johan Hedberg314b2382011-04-27 10:29:57 -04004614
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004615void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004616{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004617 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004618 struct pending_cmd *cmd;
4619
Andre Guedes343fb142011-11-22 17:14:19 -03004620 BT_DBG("%s discovering %u", hdev->name, discovering);
4621
Johan Hedberg164a6e72011-11-01 17:06:44 +02004622 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004623 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004624 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004625 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004626
4627 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004628 u8 type = hdev->discovery.type;
4629
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004630 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4631 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004632 mgmt_pending_remove(cmd);
4633 }
4634
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004635 memset(&ev, 0, sizeof(ev));
4636 ev.type = hdev->discovery.type;
4637 ev.discovering = discovering;
4638
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004639 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004640}
Antti Julku5e762442011-08-25 16:48:02 +03004641
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004642int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004643{
4644 struct pending_cmd *cmd;
4645 struct mgmt_ev_device_blocked ev;
4646
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004647 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004648
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004649 bacpy(&ev.addr.bdaddr, bdaddr);
4650 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004651
Johan Hedberg744cf192011-11-08 20:40:14 +02004652 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004653 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004654}
4655
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004656int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004657{
4658 struct pending_cmd *cmd;
4659 struct mgmt_ev_device_unblocked ev;
4660
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004661 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004662
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004663 bacpy(&ev.addr.bdaddr, bdaddr);
4664 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004665
Johan Hedberg744cf192011-11-08 20:40:14 +02004666 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004667 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004668}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004669
4670static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4671{
4672 BT_DBG("%s status %u", hdev->name, status);
4673
4674 /* Clear the advertising mgmt setting if we failed to re-enable it */
4675 if (status) {
4676 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004677 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004678 }
4679}
4680
4681void mgmt_reenable_advertising(struct hci_dev *hdev)
4682{
4683 struct hci_request req;
4684
4685 if (hdev->conn_hash.le_num)
4686 return;
4687
4688 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4689 return;
4690
4691 hci_req_init(&req, hdev);
4692 enable_advertising(&req);
4693
4694 /* If this fails we have no option but to let user space know
4695 * that we've disabled advertising.
4696 */
4697 if (hci_req_run(&req, adv_enable_complete) < 0) {
4698 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004699 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004700 }
4701}