blob: 9702079833fc0d189030821095b01bea7a63742b [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 Hedberg84bde9d2012-01-25 14:21:06 +0200414 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_SSP;
Johan 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 Hedberg84bde9d2012-01-25 14:21:06 +0200595 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500596 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300597
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200598 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500599 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300600
601 memset(&cp, 0, sizeof(cp));
602
603 create_eir(hdev, cp.data);
604
605 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500606 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300607
608 memcpy(hdev->eir, cp.data, sizeof(cp.data));
609
Johan Hedberg890ea892013-03-15 17:06:52 -0500610 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300611}
612
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200613static u8 get_service_classes(struct hci_dev *hdev)
614{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300615 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200616 u8 val = 0;
617
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300618 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200619 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620
621 return val;
622}
623
Johan Hedberg890ea892013-03-15 17:06:52 -0500624static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200625{
Johan Hedberg890ea892013-03-15 17:06:52 -0500626 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627 u8 cod[3];
628
629 BT_DBG("%s", hdev->name);
630
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200631 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500632 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200633
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200634 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500635 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200636
637 cod[0] = hdev->minor_class;
638 cod[1] = hdev->major_class;
639 cod[2] = get_service_classes(hdev);
640
641 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500642 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200643
Johan Hedberg890ea892013-03-15 17:06:52 -0500644 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200645}
646
Johan Hedberg7d785252011-12-15 00:47:39 +0200647static void service_cache_off(struct work_struct *work)
648{
649 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300650 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500651 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200652
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200653 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200654 return;
655
Johan Hedberg890ea892013-03-15 17:06:52 -0500656 hci_req_init(&req, hdev);
657
Johan Hedberg7d785252011-12-15 00:47:39 +0200658 hci_dev_lock(hdev);
659
Johan Hedberg890ea892013-03-15 17:06:52 -0500660 update_eir(&req);
661 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200662
663 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500664
665 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200666}
667
Johan Hedberg6a919082012-02-28 06:17:26 +0200668static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200669{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200670 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200671 return;
672
Johan Hedberg4f87da82012-03-02 19:55:56 +0200673 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200674
Johan Hedberg4f87da82012-03-02 19:55:56 +0200675 /* Non-mgmt controlled devices get this bit set
676 * implicitly so that pairing works for them, however
677 * for mgmt we require user-space to explicitly enable
678 * it
679 */
680 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200681}
682
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200683static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300684 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200685{
686 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200687
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200688 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300690 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200691
Johan Hedberg03811012010-12-08 00:21:06 +0200692 memset(&rp, 0, sizeof(rp));
693
Johan Hedberg03811012010-12-08 00:21:06 +0200694 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200695
696 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200697 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200698
699 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
700 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
701
702 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200703
704 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200705 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200706
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300707 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200708
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200709 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300710 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200711}
712
713static void mgmt_pending_free(struct pending_cmd *cmd)
714{
715 sock_put(cmd->sk);
716 kfree(cmd->param);
717 kfree(cmd);
718}
719
720static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300721 struct hci_dev *hdev, void *data,
722 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200723{
724 struct pending_cmd *cmd;
725
Andre Guedes12b94562012-06-07 19:05:45 -0300726 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200727 if (!cmd)
728 return NULL;
729
730 cmd->opcode = opcode;
731 cmd->index = hdev->id;
732
Andre Guedes12b94562012-06-07 19:05:45 -0300733 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200734 if (!cmd->param) {
735 kfree(cmd);
736 return NULL;
737 }
738
739 if (data)
740 memcpy(cmd->param, data, len);
741
742 cmd->sk = sk;
743 sock_hold(sk);
744
745 list_add(&cmd->list, &hdev->mgmt_pending);
746
747 return cmd;
748}
749
750static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300751 void (*cb)(struct pending_cmd *cmd,
752 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300753 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200754{
Andre Guedesa3d09352013-02-01 11:21:30 -0300755 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Andre Guedesa3d09352013-02-01 11:21:30 -0300757 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200758 if (opcode > 0 && cmd->opcode != opcode)
759 continue;
760
761 cb(cmd, data);
762 }
763}
764
765static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
766{
767 struct pending_cmd *cmd;
768
769 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
770 if (cmd->opcode == opcode)
771 return cmd;
772 }
773
774 return NULL;
775}
776
777static void mgmt_pending_remove(struct pending_cmd *cmd)
778{
779 list_del(&cmd->list);
780 mgmt_pending_free(cmd);
781}
782
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200783static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200784{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200785 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200786
Johan 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;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001191 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001193 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001194
Johan Hedberga7e80f22013-01-09 16:05:19 +02001195 if (cp->val != 0x00 && cp->val != 0x01)
1196 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1197 MGMT_STATUS_INVALID_PARAMS);
1198
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001199 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001200
1201 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001202 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001203 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001204 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001205
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001206 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207 if (err < 0)
1208 goto failed;
1209
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001210 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211
1212failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001213 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001214 return err;
1215}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001216
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001217static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1218 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001219{
1220 struct mgmt_mode *cp = data;
1221 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001222 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001223 int err;
1224
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001225 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001226
Johan Hedberge6fe7982013-10-02 15:45:22 +03001227 status = mgmt_bredr_support(hdev);
1228 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001229 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001230 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001231
Johan Hedberga7e80f22013-01-09 16:05:19 +02001232 if (cp->val != 0x00 && cp->val != 0x01)
1233 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1234 MGMT_STATUS_INVALID_PARAMS);
1235
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001236 hci_dev_lock(hdev);
1237
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001238 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001239 bool changed = false;
1240
1241 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001242 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001243 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1244 changed = true;
1245 }
1246
1247 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1248 if (err < 0)
1249 goto failed;
1250
1251 if (changed)
1252 err = new_settings(hdev, sk);
1253
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001254 goto failed;
1255 }
1256
1257 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001258 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001259 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001260 goto failed;
1261 }
1262
1263 val = !!cp->val;
1264
1265 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1266 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1267 goto failed;
1268 }
1269
1270 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1271 if (!cmd) {
1272 err = -ENOMEM;
1273 goto failed;
1274 }
1275
1276 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1277 if (err < 0) {
1278 mgmt_pending_remove(cmd);
1279 goto failed;
1280 }
1281
1282failed:
1283 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001284 return err;
1285}
1286
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001287static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001288{
1289 struct mgmt_mode *cp = data;
1290 struct pending_cmd *cmd;
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001291 u8 val, status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001292 int err;
1293
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001294 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001295
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001296 status = mgmt_bredr_support(hdev);
1297 if (status)
1298 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1299
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001300 if (!lmp_ssp_capable(hdev))
1301 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1302 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001303
Johan Hedberga7e80f22013-01-09 16:05:19 +02001304 if (cp->val != 0x00 && cp->val != 0x01)
1305 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1306 MGMT_STATUS_INVALID_PARAMS);
1307
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001308 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001309
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001310 val = !!cp->val;
1311
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001312 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001313 bool changed = false;
1314
1315 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1316 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1317 changed = true;
1318 }
1319
1320 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1321 if (err < 0)
1322 goto failed;
1323
1324 if (changed)
1325 err = new_settings(hdev, sk);
1326
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001327 goto failed;
1328 }
1329
1330 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001331 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1332 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001333 goto failed;
1334 }
1335
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001336 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1337 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1338 goto failed;
1339 }
1340
1341 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1342 if (!cmd) {
1343 err = -ENOMEM;
1344 goto failed;
1345 }
1346
1347 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1348 if (err < 0) {
1349 mgmt_pending_remove(cmd);
1350 goto failed;
1351 }
1352
1353failed:
1354 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001355 return err;
1356}
1357
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001358static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001359{
1360 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001361 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001362 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001363 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001364
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001365 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001366
Johan Hedberge6fe7982013-10-02 15:45:22 +03001367 status = mgmt_bredr_support(hdev);
1368 if (status)
1369 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001370
Johan Hedberga7e80f22013-01-09 16:05:19 +02001371 if (cp->val != 0x00 && cp->val != 0x01)
1372 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1373 MGMT_STATUS_INVALID_PARAMS);
1374
Marcel Holtmannee392692013-10-01 22:59:23 -07001375 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001376
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001377 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001378 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001379 } else {
1380 if (hdev_is_powered(hdev)) {
1381 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1382 MGMT_STATUS_REJECTED);
1383 goto unlock;
1384 }
1385
Marcel Holtmannee392692013-10-01 22:59:23 -07001386 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001387 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001388
1389 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1390 if (err < 0)
1391 goto unlock;
1392
1393 if (changed)
1394 err = new_settings(hdev, sk);
1395
1396unlock:
1397 hci_dev_unlock(hdev);
1398 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001399}
1400
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001401static void enable_advertising(struct hci_request *req)
1402{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001403 struct hci_dev *hdev = req->hdev;
1404 struct hci_cp_le_set_adv_param cp;
1405 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001406
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001407 memset(&cp, 0, sizeof(cp));
1408 cp.min_interval = __constant_cpu_to_le16(0x0800);
1409 cp.max_interval = __constant_cpu_to_le16(0x0800);
1410 cp.type = LE_ADV_IND;
1411 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1412 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1413 else
1414 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1415 cp.channel_map = 0x07;
1416
1417 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1418
1419 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001420}
1421
1422static void disable_advertising(struct hci_request *req)
1423{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001424 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001425
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001426 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001427}
1428
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001429static void le_enable_complete(struct hci_dev *hdev, u8 status)
1430{
1431 struct cmd_lookup match = { NULL, hdev };
1432
1433 if (status) {
1434 u8 mgmt_err = mgmt_status(status);
1435
1436 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1437 &mgmt_err);
1438 return;
1439 }
1440
1441 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1442
1443 new_settings(hdev, match.sk);
1444
1445 if (match.sk)
1446 sock_put(match.sk);
1447}
1448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001450{
1451 struct mgmt_mode *cp = data;
1452 struct hci_cp_write_le_host_supported hci_cp;
1453 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001454 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001455 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001456 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001457
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001458 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001459
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001460 if (!lmp_le_capable(hdev))
1461 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1462 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001463
Johan Hedberga7e80f22013-01-09 16:05:19 +02001464 if (cp->val != 0x00 && cp->val != 0x01)
1465 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1466 MGMT_STATUS_INVALID_PARAMS);
1467
Johan Hedbergc73eee92013-04-19 18:35:21 +03001468 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001469 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001470 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1471 MGMT_STATUS_REJECTED);
1472
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001473 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001474
1475 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001476 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001477
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001478 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001479 bool changed = false;
1480
1481 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1482 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1483 changed = true;
1484 }
1485
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001486 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1487 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001488 changed = true;
1489 }
1490
Johan Hedberg06199cf2012-02-22 16:37:11 +02001491 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1492 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001493 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001494
1495 if (changed)
1496 err = new_settings(hdev, sk);
1497
Johan Hedberg1de028c2012-02-29 19:55:35 -08001498 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001499 }
1500
Johan Hedberg4375f102013-09-25 13:26:10 +03001501 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1502 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001503 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001504 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001505 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001506 }
1507
1508 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1509 if (!cmd) {
1510 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001511 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001512 }
1513
1514 memset(&hci_cp, 0, sizeof(hci_cp));
1515
1516 if (val) {
1517 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001518 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001519 }
1520
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001521 hci_req_init(&req, hdev);
1522
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001523 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1524 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001525
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001526 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1527 &hci_cp);
1528
1529 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301530 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001531 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001532
Johan Hedberg1de028c2012-02-29 19:55:35 -08001533unlock:
1534 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001535 return err;
1536}
1537
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001538/* This is a helper function to test for pending mgmt commands that can
1539 * cause CoD or EIR HCI commands. We can only allow one such pending
1540 * mgmt command at a time since otherwise we cannot easily track what
1541 * the current values are, will be, and based on that calculate if a new
1542 * HCI command needs to be sent and if yes with what value.
1543 */
1544static bool pending_eir_or_class(struct hci_dev *hdev)
1545{
1546 struct pending_cmd *cmd;
1547
1548 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1549 switch (cmd->opcode) {
1550 case MGMT_OP_ADD_UUID:
1551 case MGMT_OP_REMOVE_UUID:
1552 case MGMT_OP_SET_DEV_CLASS:
1553 case MGMT_OP_SET_POWERED:
1554 return true;
1555 }
1556 }
1557
1558 return false;
1559}
1560
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001561static const u8 bluetooth_base_uuid[] = {
1562 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1563 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1564};
1565
1566static u8 get_uuid_size(const u8 *uuid)
1567{
1568 u32 val;
1569
1570 if (memcmp(uuid, bluetooth_base_uuid, 12))
1571 return 128;
1572
1573 val = get_unaligned_le32(&uuid[12]);
1574 if (val > 0xffff)
1575 return 32;
1576
1577 return 16;
1578}
1579
Johan Hedberg92da6092013-03-15 17:06:55 -05001580static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1581{
1582 struct pending_cmd *cmd;
1583
1584 hci_dev_lock(hdev);
1585
1586 cmd = mgmt_pending_find(mgmt_op, hdev);
1587 if (!cmd)
1588 goto unlock;
1589
1590 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1591 hdev->dev_class, 3);
1592
1593 mgmt_pending_remove(cmd);
1594
1595unlock:
1596 hci_dev_unlock(hdev);
1597}
1598
1599static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1600{
1601 BT_DBG("status 0x%02x", status);
1602
1603 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1604}
1605
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001606static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001607{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001608 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001609 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001610 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001611 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001612 int err;
1613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001614 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001615
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001616 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001617
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001618 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001619 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001620 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001621 goto failed;
1622 }
1623
Andre Guedes92c4c202012-06-07 19:05:44 -03001624 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625 if (!uuid) {
1626 err = -ENOMEM;
1627 goto failed;
1628 }
1629
1630 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001631 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001632 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001633
Johan Hedbergde66aa62013-01-27 00:31:27 +02001634 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001635
Johan Hedberg890ea892013-03-15 17:06:52 -05001636 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001637
Johan Hedberg890ea892013-03-15 17:06:52 -05001638 update_class(&req);
1639 update_eir(&req);
1640
Johan Hedberg92da6092013-03-15 17:06:55 -05001641 err = hci_req_run(&req, add_uuid_complete);
1642 if (err < 0) {
1643 if (err != -ENODATA)
1644 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001646 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001647 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001648 goto failed;
1649 }
1650
1651 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001652 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001653 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001654 goto failed;
1655 }
1656
1657 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001658
1659failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001660 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001661 return err;
1662}
1663
Johan Hedberg24b78d02012-02-23 23:24:30 +02001664static bool enable_service_cache(struct hci_dev *hdev)
1665{
1666 if (!hdev_is_powered(hdev))
1667 return false;
1668
1669 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001670 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1671 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001672 return true;
1673 }
1674
1675 return false;
1676}
1677
Johan Hedberg92da6092013-03-15 17:06:55 -05001678static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1679{
1680 BT_DBG("status 0x%02x", status);
1681
1682 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1683}
1684
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001685static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001686 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001687{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001688 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001689 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001690 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001691 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05001692 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001693 int err, found;
1694
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001695 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001697 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001698
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001699 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001700 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001701 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001702 goto unlock;
1703 }
1704
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001705 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1706 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001707
Johan Hedberg24b78d02012-02-23 23:24:30 +02001708 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001709 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001710 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001711 goto unlock;
1712 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001713
Johan Hedberg9246a862012-02-23 21:33:16 +02001714 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001715 }
1716
1717 found = 0;
1718
Johan Hedberg056341c2013-01-27 00:31:30 +02001719 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001720 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1721 continue;
1722
1723 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001724 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001725 found++;
1726 }
1727
1728 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001729 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001731 goto unlock;
1732 }
1733
Johan Hedberg9246a862012-02-23 21:33:16 +02001734update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001735 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001736
Johan Hedberg890ea892013-03-15 17:06:52 -05001737 update_class(&req);
1738 update_eir(&req);
1739
Johan Hedberg92da6092013-03-15 17:06:55 -05001740 err = hci_req_run(&req, remove_uuid_complete);
1741 if (err < 0) {
1742 if (err != -ENODATA)
1743 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001745 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001746 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001747 goto unlock;
1748 }
1749
1750 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001751 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001752 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001753 goto unlock;
1754 }
1755
1756 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001757
1758unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001759 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001760 return err;
1761}
1762
Johan Hedberg92da6092013-03-15 17:06:55 -05001763static void set_class_complete(struct hci_dev *hdev, u8 status)
1764{
1765 BT_DBG("status 0x%02x", status);
1766
1767 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1768}
1769
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001770static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001771 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001772{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001773 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001774 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001775 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001776 int err;
1777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001778 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001779
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001780 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001781 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1782 MGMT_STATUS_NOT_SUPPORTED);
1783
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001784 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001785
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001786 if (pending_eir_or_class(hdev)) {
1787 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1788 MGMT_STATUS_BUSY);
1789 goto unlock;
1790 }
1791
1792 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1793 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1794 MGMT_STATUS_INVALID_PARAMS);
1795 goto unlock;
1796 }
1797
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001798 hdev->major_class = cp->major;
1799 hdev->minor_class = cp->minor;
1800
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001801 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001802 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001803 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001804 goto unlock;
1805 }
1806
Johan Hedberg890ea892013-03-15 17:06:52 -05001807 hci_req_init(&req, hdev);
1808
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001809 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001810 hci_dev_unlock(hdev);
1811 cancel_delayed_work_sync(&hdev->service_cache);
1812 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001813 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001814 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001815
Johan Hedberg890ea892013-03-15 17:06:52 -05001816 update_class(&req);
1817
Johan Hedberg92da6092013-03-15 17:06:55 -05001818 err = hci_req_run(&req, set_class_complete);
1819 if (err < 0) {
1820 if (err != -ENODATA)
1821 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001822
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001823 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001824 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001825 goto unlock;
1826 }
1827
1828 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001829 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001830 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001831 goto unlock;
1832 }
1833
1834 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001835
Johan Hedbergb5235a62012-02-21 14:32:24 +02001836unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001837 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001838 return err;
1839}
1840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001842 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001843{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001844 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001845 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001846 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001847
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001848 BT_DBG("request for %s", hdev->name);
1849
1850 if (!lmp_bredr_capable(hdev))
1851 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1852 MGMT_STATUS_NOT_SUPPORTED);
1853
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001854 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001855
Johan Hedberg86742e12011-11-07 23:13:38 +02001856 expected_len = sizeof(*cp) + key_count *
1857 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001858 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001859 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001860 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001861 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001862 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001863 }
1864
Johan Hedberg4ae143012013-01-20 14:27:13 +02001865 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1866 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1867 MGMT_STATUS_INVALID_PARAMS);
1868
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001869 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001870 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001871
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001872 for (i = 0; i < key_count; i++) {
1873 struct mgmt_link_key_info *key = &cp->keys[i];
1874
1875 if (key->addr.type != BDADDR_BREDR)
1876 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1877 MGMT_STATUS_INVALID_PARAMS);
1878 }
1879
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001880 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001881
1882 hci_link_keys_clear(hdev);
1883
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001884 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001885 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001886 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001887 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001888
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001889 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001890 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001891
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001892 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001893 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001894 }
1895
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001896 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001897
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001898 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001899
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001900 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001901}
1902
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001903static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001904 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001905{
1906 struct mgmt_ev_device_unpaired ev;
1907
1908 bacpy(&ev.addr.bdaddr, bdaddr);
1909 ev.addr.type = addr_type;
1910
1911 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001912 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001913}
1914
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001915static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001916 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001917{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001918 struct mgmt_cp_unpair_device *cp = data;
1919 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001920 struct hci_cp_disconnect dc;
1921 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001922 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001923 int err;
1924
Johan Hedberga8a1d192011-11-10 15:54:38 +02001925 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001926 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1927 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001928
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001929 if (!bdaddr_type_is_valid(cp->addr.type))
1930 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1931 MGMT_STATUS_INVALID_PARAMS,
1932 &rp, sizeof(rp));
1933
Johan Hedberg118da702013-01-20 14:27:20 +02001934 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1935 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1936 MGMT_STATUS_INVALID_PARAMS,
1937 &rp, sizeof(rp));
1938
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001939 hci_dev_lock(hdev);
1940
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001941 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001942 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001943 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001944 goto unlock;
1945 }
1946
Andre Guedes591f47f2012-04-24 21:02:49 -03001947 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001948 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1949 else
1950 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001951
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001952 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001953 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001954 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001955 goto unlock;
1956 }
1957
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001958 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001959 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001960 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001961 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001962 else
1963 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001964 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001965 } else {
1966 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001967 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001968
Johan Hedberga8a1d192011-11-10 15:54:38 +02001969 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001970 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001971 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001972 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001973 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001974 }
1975
Johan Hedberg124f6e32012-02-09 13:50:12 +02001976 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001977 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001978 if (!cmd) {
1979 err = -ENOMEM;
1980 goto unlock;
1981 }
1982
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001983 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001984 dc.reason = 0x13; /* Remote User Terminated Connection */
1985 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1986 if (err < 0)
1987 mgmt_pending_remove(cmd);
1988
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001989unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001990 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001991 return err;
1992}
1993
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001994static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001995 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001996{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001997 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001998 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001999 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002000 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002001 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002002 int err;
2003
2004 BT_DBG("");
2005
Johan Hedberg06a63b12013-01-20 14:27:21 +02002006 memset(&rp, 0, sizeof(rp));
2007 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2008 rp.addr.type = cp->addr.type;
2009
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002010 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002011 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2012 MGMT_STATUS_INVALID_PARAMS,
2013 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002015 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002016
2017 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002018 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2019 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002020 goto failed;
2021 }
2022
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002023 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002024 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2025 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002026 goto failed;
2027 }
2028
Andre Guedes591f47f2012-04-24 21:02:49 -03002029 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002030 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2031 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002032 else
2033 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002034
Vishal Agarwalf9607272012-06-13 05:32:43 +05302035 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002036 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2037 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002038 goto failed;
2039 }
2040
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002041 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002042 if (!cmd) {
2043 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002044 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002045 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002046
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002047 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002048 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002049
2050 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2051 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002052 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002053
2054failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002055 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002056 return err;
2057}
2058
Andre Guedes57c14772012-04-24 21:02:50 -03002059static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002060{
2061 switch (link_type) {
2062 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002063 switch (addr_type) {
2064 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002065 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002066
Johan Hedberg48264f02011-11-09 13:58:58 +02002067 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002068 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002069 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002070 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002071
Johan Hedberg4c659c32011-11-07 23:13:39 +02002072 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002073 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002074 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002075 }
2076}
2077
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002078static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2079 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002080{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002081 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002082 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002083 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002084 int err;
2085 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002086
2087 BT_DBG("");
2088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002090
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002091 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002094 goto unlock;
2095 }
2096
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002097 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002098 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2099 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002100 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002101 }
2102
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002103 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002104 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002105 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002106 err = -ENOMEM;
2107 goto unlock;
2108 }
2109
Johan Hedberg2784eb42011-01-21 13:56:35 +02002110 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002111 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002112 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2113 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002114 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002115 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002116 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002117 continue;
2118 i++;
2119 }
2120
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002121 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002122
Johan Hedberg4c659c32011-11-07 23:13:39 +02002123 /* Recalculate length in case of filtered SCO connections, etc */
2124 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002126 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002127 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002128
Johan Hedberga38528f2011-01-22 06:46:43 +02002129 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002130
2131unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002132 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002133 return err;
2134}
2135
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002136static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002137 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002138{
2139 struct pending_cmd *cmd;
2140 int err;
2141
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002142 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002143 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002144 if (!cmd)
2145 return -ENOMEM;
2146
Johan Hedbergd8457692012-02-17 14:24:57 +02002147 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002148 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002149 if (err < 0)
2150 mgmt_pending_remove(cmd);
2151
2152 return err;
2153}
2154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002155static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002156 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002157{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002158 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002159 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002160 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002161 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002162 int err;
2163
2164 BT_DBG("");
2165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002166 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002167
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002168 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002169 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002170 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002171 goto failed;
2172 }
2173
Johan Hedbergd8457692012-02-17 14:24:57 +02002174 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002175 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002176 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002177 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002178 goto failed;
2179 }
2180
2181 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002182 struct mgmt_cp_pin_code_neg_reply ncp;
2183
2184 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002185
2186 BT_ERR("PIN code is not 16 bytes long");
2187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002189 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002190 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002191 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002192
2193 goto failed;
2194 }
2195
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002196 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002197 if (!cmd) {
2198 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002199 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002200 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002201
Johan Hedbergd8457692012-02-17 14:24:57 +02002202 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002203 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002204 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002205
2206 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2207 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002208 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002209
2210failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002211 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002212 return err;
2213}
2214
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002215static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2216 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002217{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002218 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002219
2220 BT_DBG("");
2221
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002222 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002223
2224 hdev->io_capability = cp->io_capability;
2225
2226 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002227 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002230
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2232 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002233}
2234
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002235static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002236{
2237 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002238 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002239
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002240 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002241 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2242 continue;
2243
Johan Hedberge9a416b2011-02-19 12:05:56 -03002244 if (cmd->user_data != conn)
2245 continue;
2246
2247 return cmd;
2248 }
2249
2250 return NULL;
2251}
2252
2253static void pairing_complete(struct pending_cmd *cmd, u8 status)
2254{
2255 struct mgmt_rp_pair_device rp;
2256 struct hci_conn *conn = cmd->user_data;
2257
Johan Hedbergba4e5642011-11-11 00:07:34 +02002258 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002259 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002260
Johan Hedbergaee9b212012-02-18 15:07:59 +02002261 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002262 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002263
2264 /* So we don't get further callbacks for this connection */
2265 conn->connect_cfm_cb = NULL;
2266 conn->security_cfm_cb = NULL;
2267 conn->disconn_cfm_cb = NULL;
2268
David Herrmann76a68ba2013-04-06 20:28:37 +02002269 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002270
Johan Hedberga664b5b2011-02-19 12:06:02 -03002271 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002272}
2273
2274static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2275{
2276 struct pending_cmd *cmd;
2277
2278 BT_DBG("status %u", status);
2279
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002280 cmd = find_pairing(conn);
2281 if (!cmd)
2282 BT_DBG("Unable to find a pending command");
2283 else
Johan Hedberge2113262012-02-18 15:20:03 +02002284 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002285}
2286
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302287static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2288{
2289 struct pending_cmd *cmd;
2290
2291 BT_DBG("status %u", status);
2292
2293 if (!status)
2294 return;
2295
2296 cmd = find_pairing(conn);
2297 if (!cmd)
2298 BT_DBG("Unable to find a pending command");
2299 else
2300 pairing_complete(cmd, mgmt_status(status));
2301}
2302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002303static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002306 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002307 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002308 struct pending_cmd *cmd;
2309 u8 sec_level, auth_type;
2310 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002311 int err;
2312
2313 BT_DBG("");
2314
Szymon Jancf950a30e2013-01-18 12:48:07 +01002315 memset(&rp, 0, sizeof(rp));
2316 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2317 rp.addr.type = cp->addr.type;
2318
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002319 if (!bdaddr_type_is_valid(cp->addr.type))
2320 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2321 MGMT_STATUS_INVALID_PARAMS,
2322 &rp, sizeof(rp));
2323
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002324 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002325
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002326 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002327 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2328 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002329 goto unlock;
2330 }
2331
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002332 sec_level = BT_SECURITY_MEDIUM;
2333 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002334 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002335 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002336 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002337
Andre Guedes591f47f2012-04-24 21:02:49 -03002338 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002339 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2340 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002341 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002342 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2343 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002344
Ville Tervo30e76272011-02-22 16:10:53 -03002345 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002346 int status;
2347
2348 if (PTR_ERR(conn) == -EBUSY)
2349 status = MGMT_STATUS_BUSY;
2350 else
2351 status = MGMT_STATUS_CONNECT_FAILED;
2352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002353 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002354 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002355 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002356 goto unlock;
2357 }
2358
2359 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002360 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002361 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002362 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002363 goto unlock;
2364 }
2365
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002366 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002367 if (!cmd) {
2368 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002369 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002370 goto unlock;
2371 }
2372
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002373 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002374 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002375 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302376 else
2377 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002378
Johan Hedberge9a416b2011-02-19 12:05:56 -03002379 conn->security_cfm_cb = pairing_complete_cb;
2380 conn->disconn_cfm_cb = pairing_complete_cb;
2381 conn->io_capability = cp->io_cap;
2382 cmd->user_data = conn;
2383
2384 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002385 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002386 pairing_complete(cmd, 0);
2387
2388 err = 0;
2389
2390unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002391 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002392 return err;
2393}
2394
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002395static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2396 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002397{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002398 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002399 struct pending_cmd *cmd;
2400 struct hci_conn *conn;
2401 int err;
2402
2403 BT_DBG("");
2404
Johan Hedberg28424702012-02-02 04:02:29 +02002405 hci_dev_lock(hdev);
2406
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002407 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002408 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002409 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002410 goto unlock;
2411 }
2412
Johan Hedberg28424702012-02-02 04:02:29 +02002413 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2414 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002415 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002417 goto unlock;
2418 }
2419
2420 conn = cmd->user_data;
2421
2422 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002423 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002425 goto unlock;
2426 }
2427
2428 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2429
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002430 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002431 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002432unlock:
2433 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002434 return err;
2435}
2436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002437static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002438 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002439 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002440{
Johan Hedberga5c29682011-02-19 12:05:57 -03002441 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002442 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002443 int err;
2444
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002445 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002446
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002447 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002448 err = cmd_complete(sk, hdev->id, mgmt_op,
2449 MGMT_STATUS_NOT_POWERED, addr,
2450 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002451 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002452 }
2453
Johan Hedberg1707c602013-03-15 17:07:15 -05002454 if (addr->type == BDADDR_BREDR)
2455 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002456 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002457 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002458
Johan Hedberg272d90d2012-02-09 15:26:12 +02002459 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002460 err = cmd_complete(sk, hdev->id, mgmt_op,
2461 MGMT_STATUS_NOT_CONNECTED, addr,
2462 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002463 goto done;
2464 }
2465
Johan Hedberg1707c602013-03-15 17:07:15 -05002466 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002467 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002468 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002469
Brian Gix5fe57d92011-12-21 16:12:13 -08002470 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002471 err = cmd_complete(sk, hdev->id, mgmt_op,
2472 MGMT_STATUS_SUCCESS, addr,
2473 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002474 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002475 err = cmd_complete(sk, hdev->id, mgmt_op,
2476 MGMT_STATUS_FAILED, addr,
2477 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002478
Brian Gix47c15e22011-11-16 13:53:14 -08002479 goto done;
2480 }
2481
Johan Hedberg1707c602013-03-15 17:07:15 -05002482 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002483 if (!cmd) {
2484 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002485 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002486 }
2487
Brian Gix0df4c182011-11-16 13:53:13 -08002488 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002489 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2490 struct hci_cp_user_passkey_reply cp;
2491
Johan Hedberg1707c602013-03-15 17:07:15 -05002492 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002493 cp.passkey = passkey;
2494 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2495 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002496 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2497 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002498
Johan Hedberga664b5b2011-02-19 12:06:02 -03002499 if (err < 0)
2500 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002501
Brian Gix0df4c182011-11-16 13:53:13 -08002502done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002503 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002504 return err;
2505}
2506
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302507static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2508 void *data, u16 len)
2509{
2510 struct mgmt_cp_pin_code_neg_reply *cp = data;
2511
2512 BT_DBG("");
2513
Johan Hedberg1707c602013-03-15 17:07:15 -05002514 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302515 MGMT_OP_PIN_CODE_NEG_REPLY,
2516 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2517}
2518
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002519static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2520 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002521{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002522 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002523
2524 BT_DBG("");
2525
2526 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002527 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002528 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002529
Johan Hedberg1707c602013-03-15 17:07:15 -05002530 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002531 MGMT_OP_USER_CONFIRM_REPLY,
2532 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002533}
2534
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002535static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002537{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002538 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002539
2540 BT_DBG("");
2541
Johan Hedberg1707c602013-03-15 17:07:15 -05002542 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002543 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2544 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002545}
2546
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2548 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002549{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002550 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002551
2552 BT_DBG("");
2553
Johan Hedberg1707c602013-03-15 17:07:15 -05002554 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 MGMT_OP_USER_PASSKEY_REPLY,
2556 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002557}
2558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002559static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002560 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002561{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002562 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002563
2564 BT_DBG("");
2565
Johan Hedberg1707c602013-03-15 17:07:15 -05002566 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002567 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2568 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002569}
2570
Johan Hedberg13928972013-03-15 17:07:00 -05002571static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002572{
Johan Hedberg13928972013-03-15 17:07:00 -05002573 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002574 struct hci_cp_write_local_name cp;
2575
Johan Hedberg13928972013-03-15 17:07:00 -05002576 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002577
Johan Hedberg890ea892013-03-15 17:06:52 -05002578 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002579}
2580
Johan Hedberg13928972013-03-15 17:07:00 -05002581static void set_name_complete(struct hci_dev *hdev, u8 status)
2582{
2583 struct mgmt_cp_set_local_name *cp;
2584 struct pending_cmd *cmd;
2585
2586 BT_DBG("status 0x%02x", status);
2587
2588 hci_dev_lock(hdev);
2589
2590 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2591 if (!cmd)
2592 goto unlock;
2593
2594 cp = cmd->param;
2595
2596 if (status)
2597 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2598 mgmt_status(status));
2599 else
2600 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2601 cp, sizeof(*cp));
2602
2603 mgmt_pending_remove(cmd);
2604
2605unlock:
2606 hci_dev_unlock(hdev);
2607}
2608
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002609static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002610 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002611{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002612 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002613 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002614 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002615 int err;
2616
2617 BT_DBG("");
2618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002619 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002620
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002621 /* If the old values are the same as the new ones just return a
2622 * direct command complete event.
2623 */
2624 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2625 !memcmp(hdev->short_name, cp->short_name,
2626 sizeof(hdev->short_name))) {
2627 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2628 data, len);
2629 goto failed;
2630 }
2631
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002632 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002633
Johan Hedbergb5235a62012-02-21 14:32:24 +02002634 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002635 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002636
2637 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002639 if (err < 0)
2640 goto failed;
2641
2642 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002643 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002644
Johan Hedbergb5235a62012-02-21 14:32:24 +02002645 goto failed;
2646 }
2647
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002648 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002649 if (!cmd) {
2650 err = -ENOMEM;
2651 goto failed;
2652 }
2653
Johan Hedberg13928972013-03-15 17:07:00 -05002654 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2655
Johan Hedberg890ea892013-03-15 17:06:52 -05002656 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002657
2658 if (lmp_bredr_capable(hdev)) {
2659 update_name(&req);
2660 update_eir(&req);
2661 }
2662
2663 if (lmp_le_capable(hdev))
2664 hci_update_ad(&req);
2665
Johan Hedberg13928972013-03-15 17:07:00 -05002666 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002667 if (err < 0)
2668 mgmt_pending_remove(cmd);
2669
2670failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002671 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002672 return err;
2673}
2674
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002675static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002676 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002677{
Szymon Jancc35938b2011-03-22 13:12:21 +01002678 struct pending_cmd *cmd;
2679 int err;
2680
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002681 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002682
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002683 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002684
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002685 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002686 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002687 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002688 goto unlock;
2689 }
2690
Andre Guedes9a1a1992012-07-24 15:03:48 -03002691 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002692 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002693 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002694 goto unlock;
2695 }
2696
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002697 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002700 goto unlock;
2701 }
2702
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002703 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002704 if (!cmd) {
2705 err = -ENOMEM;
2706 goto unlock;
2707 }
2708
2709 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2710 if (err < 0)
2711 mgmt_pending_remove(cmd);
2712
2713unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002714 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002715 return err;
2716}
2717
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002718static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002719 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002720{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002721 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002722 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002723 int err;
2724
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002725 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002726
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002727 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002728
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002729 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002730 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002731 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002732 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002733 else
Szymon Janca6785be2012-12-13 15:11:21 +01002734 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002736 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002737 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002738
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002739 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002740 return err;
2741}
2742
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002743static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002744 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002745{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002746 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002747 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002748 int err;
2749
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002750 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002751
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002752 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002753
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002754 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002755 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002756 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002757 else
Szymon Janca6785be2012-12-13 15:11:21 +01002758 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002762
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002763 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002764 return err;
2765}
2766
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002767static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2768{
2769 struct pending_cmd *cmd;
2770 u8 type;
2771 int err;
2772
2773 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2774
2775 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2776 if (!cmd)
2777 return -ENOENT;
2778
2779 type = hdev->discovery.type;
2780
2781 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2782 &type, sizeof(type));
2783 mgmt_pending_remove(cmd);
2784
2785 return err;
2786}
2787
Andre Guedes7c307722013-04-30 15:29:28 -03002788static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2789{
2790 BT_DBG("status %d", status);
2791
2792 if (status) {
2793 hci_dev_lock(hdev);
2794 mgmt_start_discovery_failed(hdev, status);
2795 hci_dev_unlock(hdev);
2796 return;
2797 }
2798
2799 hci_dev_lock(hdev);
2800 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2801 hci_dev_unlock(hdev);
2802
2803 switch (hdev->discovery.type) {
2804 case DISCOV_TYPE_LE:
2805 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002806 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002807 break;
2808
2809 case DISCOV_TYPE_INTERLEAVED:
2810 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002811 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002812 break;
2813
2814 case DISCOV_TYPE_BREDR:
2815 break;
2816
2817 default:
2818 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2819 }
2820}
2821
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002822static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002823 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002824{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002825 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002826 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002827 struct hci_cp_le_set_scan_param param_cp;
2828 struct hci_cp_le_set_scan_enable enable_cp;
2829 struct hci_cp_inquiry inq_cp;
2830 struct hci_request req;
2831 /* General inquiry access code (GIAC) */
2832 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002833 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002834 int err;
2835
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002836 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002837
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002838 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002839
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002840 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002841 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002842 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002843 goto failed;
2844 }
2845
Andre Guedes642be6c2012-03-21 00:03:37 -03002846 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2847 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2848 MGMT_STATUS_BUSY);
2849 goto failed;
2850 }
2851
Johan Hedbergff9ef572012-01-04 14:23:45 +02002852 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002853 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002854 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002855 goto failed;
2856 }
2857
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002858 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002859 if (!cmd) {
2860 err = -ENOMEM;
2861 goto failed;
2862 }
2863
Andre Guedes4aab14e2012-02-17 20:39:36 -03002864 hdev->discovery.type = cp->type;
2865
Andre Guedes7c307722013-04-30 15:29:28 -03002866 hci_req_init(&req, hdev);
2867
Andre Guedes4aab14e2012-02-17 20:39:36 -03002868 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002869 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002870 status = mgmt_bredr_support(hdev);
2871 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002872 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002873 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002874 mgmt_pending_remove(cmd);
2875 goto failed;
2876 }
2877
Andre Guedes7c307722013-04-30 15:29:28 -03002878 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2879 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2880 MGMT_STATUS_BUSY);
2881 mgmt_pending_remove(cmd);
2882 goto failed;
2883 }
2884
2885 hci_inquiry_cache_flush(hdev);
2886
2887 memset(&inq_cp, 0, sizeof(inq_cp));
2888 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002889 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002890 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002891 break;
2892
2893 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002894 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002895 status = mgmt_le_support(hdev);
2896 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002897 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002898 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002899 mgmt_pending_remove(cmd);
2900 goto failed;
2901 }
2902
Andre Guedes7c307722013-04-30 15:29:28 -03002903 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002904 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002905 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2906 MGMT_STATUS_NOT_SUPPORTED);
2907 mgmt_pending_remove(cmd);
2908 goto failed;
2909 }
2910
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002911 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002912 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2913 MGMT_STATUS_REJECTED);
2914 mgmt_pending_remove(cmd);
2915 goto failed;
2916 }
2917
2918 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2919 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2920 MGMT_STATUS_BUSY);
2921 mgmt_pending_remove(cmd);
2922 goto failed;
2923 }
2924
2925 memset(&param_cp, 0, sizeof(param_cp));
2926 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002927 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2928 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002929 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2930 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2931 else
2932 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002933 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2934 &param_cp);
2935
2936 memset(&enable_cp, 0, sizeof(enable_cp));
2937 enable_cp.enable = LE_SCAN_ENABLE;
2938 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2939 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2940 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002941 break;
2942
Andre Guedesf39799f2012-02-17 20:39:35 -03002943 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002944 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2945 MGMT_STATUS_INVALID_PARAMS);
2946 mgmt_pending_remove(cmd);
2947 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002948 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002949
Andre Guedes7c307722013-04-30 15:29:28 -03002950 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002951 if (err < 0)
2952 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002953 else
2954 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002955
2956failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002957 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002958 return err;
2959}
2960
Andre Guedes1183fdc2013-04-30 15:29:35 -03002961static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2962{
2963 struct pending_cmd *cmd;
2964 int err;
2965
2966 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2967 if (!cmd)
2968 return -ENOENT;
2969
2970 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2971 &hdev->discovery.type, sizeof(hdev->discovery.type));
2972 mgmt_pending_remove(cmd);
2973
2974 return err;
2975}
2976
Andre Guedes0e05bba2013-04-30 15:29:33 -03002977static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2978{
2979 BT_DBG("status %d", status);
2980
2981 hci_dev_lock(hdev);
2982
2983 if (status) {
2984 mgmt_stop_discovery_failed(hdev, status);
2985 goto unlock;
2986 }
2987
2988 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2989
2990unlock:
2991 hci_dev_unlock(hdev);
2992}
2993
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002994static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002995 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002996{
Johan Hedbergd9306502012-02-20 23:25:18 +02002997 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002998 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002999 struct hci_cp_remote_name_req_cancel cp;
3000 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003001 struct hci_request req;
3002 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003003 int err;
3004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003005 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003006
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003007 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003008
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003009 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003010 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3012 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003013 goto unlock;
3014 }
3015
3016 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003017 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3019 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003020 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003021 }
3022
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003023 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003024 if (!cmd) {
3025 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003026 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003027 }
3028
Andre Guedes0e05bba2013-04-30 15:29:33 -03003029 hci_req_init(&req, hdev);
3030
Andre Guedese0d9727e2012-03-20 15:15:36 -03003031 switch (hdev->discovery.state) {
3032 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003033 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3034 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3035 } else {
3036 cancel_delayed_work(&hdev->le_scan_disable);
3037
3038 memset(&enable_cp, 0, sizeof(enable_cp));
3039 enable_cp.enable = LE_SCAN_DISABLE;
3040 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3041 sizeof(enable_cp), &enable_cp);
3042 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003043
Andre Guedese0d9727e2012-03-20 15:15:36 -03003044 break;
3045
3046 case DISCOVERY_RESOLVING:
3047 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003048 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003049 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003050 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003051 err = cmd_complete(sk, hdev->id,
3052 MGMT_OP_STOP_DISCOVERY, 0,
3053 &mgmt_cp->type,
3054 sizeof(mgmt_cp->type));
3055 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3056 goto unlock;
3057 }
3058
3059 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003060 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3061 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003062
3063 break;
3064
3065 default:
3066 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003067
3068 mgmt_pending_remove(cmd);
3069 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3070 MGMT_STATUS_FAILED, &mgmt_cp->type,
3071 sizeof(mgmt_cp->type));
3072 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003073 }
3074
Andre Guedes0e05bba2013-04-30 15:29:33 -03003075 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003076 if (err < 0)
3077 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003078 else
3079 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003080
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003081unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003082 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003083 return err;
3084}
3085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003089 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003090 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003091 int err;
3092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003093 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003094
Johan Hedberg561aafb2012-01-04 13:31:59 +02003095 hci_dev_lock(hdev);
3096
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003097 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003098 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003099 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003100 goto failed;
3101 }
3102
Johan Hedberga198e7b2012-02-17 14:27:06 +02003103 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003104 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003105 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003106 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003107 goto failed;
3108 }
3109
3110 if (cp->name_known) {
3111 e->name_state = NAME_KNOWN;
3112 list_del(&e->list);
3113 } else {
3114 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003115 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003116 }
3117
Johan Hedberge3846622013-01-09 15:29:33 +02003118 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3119 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003120
3121failed:
3122 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003123 return err;
3124}
3125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003126static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003128{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003129 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003130 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003131 int err;
3132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003133 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003134
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003135 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003136 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3137 MGMT_STATUS_INVALID_PARAMS,
3138 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003139
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003140 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003141
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003142 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003143 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003144 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003145 else
Szymon Janca6785be2012-12-13 15:11:21 +01003146 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003147
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003148 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003149 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003151 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003152
3153 return err;
3154}
3155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003156static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003157 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003158{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003159 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003160 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003161 int err;
3162
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003163 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003164
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003165 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003166 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3167 MGMT_STATUS_INVALID_PARAMS,
3168 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003169
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003170 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003171
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003172 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003173 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003174 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003175 else
Szymon Janca6785be2012-12-13 15:11:21 +01003176 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003178 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003179 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003181 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003182
3183 return err;
3184}
3185
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003186static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3187 u16 len)
3188{
3189 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003190 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003191 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003192 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003193
3194 BT_DBG("%s", hdev->name);
3195
Szymon Jancc72d4b82012-03-16 16:02:57 +01003196 source = __le16_to_cpu(cp->source);
3197
3198 if (source > 0x0002)
3199 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3200 MGMT_STATUS_INVALID_PARAMS);
3201
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003202 hci_dev_lock(hdev);
3203
Szymon Jancc72d4b82012-03-16 16:02:57 +01003204 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003205 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3206 hdev->devid_product = __le16_to_cpu(cp->product);
3207 hdev->devid_version = __le16_to_cpu(cp->version);
3208
3209 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3210
Johan Hedberg890ea892013-03-15 17:06:52 -05003211 hci_req_init(&req, hdev);
3212 update_eir(&req);
3213 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003214
3215 hci_dev_unlock(hdev);
3216
3217 return err;
3218}
3219
Johan Hedberg4375f102013-09-25 13:26:10 +03003220static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3221{
3222 struct cmd_lookup match = { NULL, hdev };
3223
3224 if (status) {
3225 u8 mgmt_err = mgmt_status(status);
3226
3227 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3228 cmd_status_rsp, &mgmt_err);
3229 return;
3230 }
3231
3232 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3233 &match);
3234
3235 new_settings(hdev, match.sk);
3236
3237 if (match.sk)
3238 sock_put(match.sk);
3239}
3240
3241static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3242{
3243 struct mgmt_mode *cp = data;
3244 struct pending_cmd *cmd;
3245 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003246 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003247 int err;
3248
3249 BT_DBG("request for %s", hdev->name);
3250
Johan Hedberge6fe7982013-10-02 15:45:22 +03003251 status = mgmt_le_support(hdev);
3252 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003253 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003254 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003255
3256 if (cp->val != 0x00 && cp->val != 0x01)
3257 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3258 MGMT_STATUS_INVALID_PARAMS);
3259
3260 hci_dev_lock(hdev);
3261
3262 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003263 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003264
3265 if (!hdev_is_powered(hdev) || val == enabled) {
3266 bool changed = false;
3267
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003268 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3269 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003270 changed = true;
3271 }
3272
3273 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3274 if (err < 0)
3275 goto unlock;
3276
3277 if (changed)
3278 err = new_settings(hdev, sk);
3279
3280 goto unlock;
3281 }
3282
3283 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3284 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3285 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3286 MGMT_STATUS_BUSY);
3287 goto unlock;
3288 }
3289
3290 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3291 if (!cmd) {
3292 err = -ENOMEM;
3293 goto unlock;
3294 }
3295
3296 hci_req_init(&req, hdev);
3297
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003298 if (val)
3299 enable_advertising(&req);
3300 else
3301 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003302
3303 err = hci_req_run(&req, set_advertising_complete);
3304 if (err < 0)
3305 mgmt_pending_remove(cmd);
3306
3307unlock:
3308 hci_dev_unlock(hdev);
3309 return err;
3310}
3311
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003312static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3313 void *data, u16 len)
3314{
3315 struct mgmt_cp_set_static_address *cp = data;
3316 int err;
3317
3318 BT_DBG("%s", hdev->name);
3319
Marcel Holtmann62af4442013-10-02 22:10:32 -07003320 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003321 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003322 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003323
3324 if (hdev_is_powered(hdev))
3325 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3326 MGMT_STATUS_REJECTED);
3327
3328 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3329 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3330 return cmd_status(sk, hdev->id,
3331 MGMT_OP_SET_STATIC_ADDRESS,
3332 MGMT_STATUS_INVALID_PARAMS);
3333
3334 /* Two most significant bits shall be set */
3335 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3336 return cmd_status(sk, hdev->id,
3337 MGMT_OP_SET_STATIC_ADDRESS,
3338 MGMT_STATUS_INVALID_PARAMS);
3339 }
3340
3341 hci_dev_lock(hdev);
3342
3343 bacpy(&hdev->static_addr, &cp->bdaddr);
3344
3345 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3346
3347 hci_dev_unlock(hdev);
3348
3349 return err;
3350}
3351
Johan Hedberg33e38b32013-03-15 17:07:05 -05003352static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3353{
3354 struct pending_cmd *cmd;
3355
3356 BT_DBG("status 0x%02x", status);
3357
3358 hci_dev_lock(hdev);
3359
3360 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3361 if (!cmd)
3362 goto unlock;
3363
3364 if (status) {
3365 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3366 mgmt_status(status));
3367 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003368 struct mgmt_mode *cp = cmd->param;
3369
3370 if (cp->val)
3371 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3372 else
3373 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3374
Johan Hedberg33e38b32013-03-15 17:07:05 -05003375 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3376 new_settings(hdev, cmd->sk);
3377 }
3378
3379 mgmt_pending_remove(cmd);
3380
3381unlock:
3382 hci_dev_unlock(hdev);
3383}
3384
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003385static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003386 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003387{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003388 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003389 struct pending_cmd *cmd;
3390 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003391 int err;
3392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003393 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003394
Johan Hedberg56f87902013-10-02 13:43:13 +03003395 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3396 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003397 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3398 MGMT_STATUS_NOT_SUPPORTED);
3399
Johan Hedberga7e80f22013-01-09 16:05:19 +02003400 if (cp->val != 0x00 && cp->val != 0x01)
3401 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3402 MGMT_STATUS_INVALID_PARAMS);
3403
Johan Hedberg5400c042012-02-21 16:40:33 +02003404 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003405 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003406 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003407
3408 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003409 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003410 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003411
3412 hci_dev_lock(hdev);
3413
Johan Hedberg05cbf292013-03-15 17:07:07 -05003414 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3415 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3416 MGMT_STATUS_BUSY);
3417 goto unlock;
3418 }
3419
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003420 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3421 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3422 hdev);
3423 goto unlock;
3424 }
3425
Johan Hedberg33e38b32013-03-15 17:07:05 -05003426 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3427 data, len);
3428 if (!cmd) {
3429 err = -ENOMEM;
3430 goto unlock;
3431 }
3432
3433 hci_req_init(&req, hdev);
3434
Johan Hedberg406d7802013-03-15 17:07:09 -05003435 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003436
3437 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003438 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003439 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003440 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003441 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003442 }
3443
Johan Hedberg33e38b32013-03-15 17:07:05 -05003444unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003445 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003446
Antti Julkuf6422ec2011-06-22 13:11:56 +03003447 return err;
3448}
3449
Johan Hedberg0663ca22013-10-02 13:43:14 +03003450static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3451{
3452 struct pending_cmd *cmd;
3453
3454 BT_DBG("status 0x%02x", status);
3455
3456 hci_dev_lock(hdev);
3457
3458 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3459 if (!cmd)
3460 goto unlock;
3461
3462 if (status) {
3463 u8 mgmt_err = mgmt_status(status);
3464
3465 /* We need to restore the flag if related HCI commands
3466 * failed.
3467 */
3468 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3469
3470 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3471 } else {
3472 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3473 new_settings(hdev, cmd->sk);
3474 }
3475
3476 mgmt_pending_remove(cmd);
3477
3478unlock:
3479 hci_dev_unlock(hdev);
3480}
3481
3482static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3483{
3484 struct mgmt_mode *cp = data;
3485 struct pending_cmd *cmd;
3486 struct hci_request req;
3487 int err;
3488
3489 BT_DBG("request for %s", hdev->name);
3490
3491 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3492 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3493 MGMT_STATUS_NOT_SUPPORTED);
3494
3495 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3496 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3497 MGMT_STATUS_REJECTED);
3498
3499 if (cp->val != 0x00 && cp->val != 0x01)
3500 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3501 MGMT_STATUS_INVALID_PARAMS);
3502
3503 hci_dev_lock(hdev);
3504
3505 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3506 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3507 goto unlock;
3508 }
3509
3510 if (!hdev_is_powered(hdev)) {
3511 if (!cp->val) {
3512 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3513 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3514 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3515 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3516 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3517 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3518 }
3519
3520 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3521
3522 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3523 if (err < 0)
3524 goto unlock;
3525
3526 err = new_settings(hdev, sk);
3527 goto unlock;
3528 }
3529
3530 /* Reject disabling when powered on */
3531 if (!cp->val) {
3532 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3533 MGMT_STATUS_REJECTED);
3534 goto unlock;
3535 }
3536
3537 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3538 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3539 MGMT_STATUS_BUSY);
3540 goto unlock;
3541 }
3542
3543 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3544 if (!cmd) {
3545 err = -ENOMEM;
3546 goto unlock;
3547 }
3548
3549 /* We need to flip the bit already here so that hci_update_ad
3550 * generates the correct flags.
3551 */
3552 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3553
3554 hci_req_init(&req, hdev);
3555 hci_update_ad(&req);
3556 err = hci_req_run(&req, set_bredr_complete);
3557 if (err < 0)
3558 mgmt_pending_remove(cmd);
3559
3560unlock:
3561 hci_dev_unlock(hdev);
3562 return err;
3563}
3564
Johan Hedberg3f706b72013-01-20 14:27:16 +02003565static bool ltk_is_valid(struct mgmt_ltk_info *key)
3566{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003567 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3568 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003569 if (key->master != 0x00 && key->master != 0x01)
3570 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003571 if (!bdaddr_type_is_le(key->addr.type))
3572 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003573 return true;
3574}
3575
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003576static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003577 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003578{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003579 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3580 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003581 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003582
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003583 BT_DBG("request for %s", hdev->name);
3584
3585 if (!lmp_le_capable(hdev))
3586 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3587 MGMT_STATUS_NOT_SUPPORTED);
3588
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003589 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003590
3591 expected_len = sizeof(*cp) + key_count *
3592 sizeof(struct mgmt_ltk_info);
3593 if (expected_len != len) {
3594 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003595 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003596 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003597 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003598 }
3599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003600 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003601
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003602 for (i = 0; i < key_count; i++) {
3603 struct mgmt_ltk_info *key = &cp->keys[i];
3604
Johan Hedberg3f706b72013-01-20 14:27:16 +02003605 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003606 return cmd_status(sk, hdev->id,
3607 MGMT_OP_LOAD_LONG_TERM_KEYS,
3608 MGMT_STATUS_INVALID_PARAMS);
3609 }
3610
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003611 hci_dev_lock(hdev);
3612
3613 hci_smp_ltks_clear(hdev);
3614
3615 for (i = 0; i < key_count; i++) {
3616 struct mgmt_ltk_info *key = &cp->keys[i];
3617 u8 type;
3618
3619 if (key->master)
3620 type = HCI_SMP_LTK;
3621 else
3622 type = HCI_SMP_LTK_SLAVE;
3623
Hemant Gupta4596fde2012-04-16 14:57:40 +05303624 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003625 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003626 type, 0, key->authenticated, key->val,
3627 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003628 }
3629
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003630 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3631 NULL, 0);
3632
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003633 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003634
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003635 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003636}
3637
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003638static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003639 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3640 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003641 bool var_len;
3642 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003643} mgmt_handlers[] = {
3644 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003645 { read_version, false, MGMT_READ_VERSION_SIZE },
3646 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3647 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3648 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3649 { set_powered, false, MGMT_SETTING_SIZE },
3650 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3651 { set_connectable, false, MGMT_SETTING_SIZE },
3652 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3653 { set_pairable, false, MGMT_SETTING_SIZE },
3654 { set_link_security, false, MGMT_SETTING_SIZE },
3655 { set_ssp, false, MGMT_SETTING_SIZE },
3656 { set_hs, false, MGMT_SETTING_SIZE },
3657 { set_le, false, MGMT_SETTING_SIZE },
3658 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3659 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3660 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3661 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3662 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3663 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3664 { disconnect, false, MGMT_DISCONNECT_SIZE },
3665 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3666 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3667 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3668 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3669 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3670 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3671 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3672 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3673 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3674 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3675 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3676 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3677 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3678 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3679 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3680 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3681 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3682 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3683 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003684 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003685 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003686 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003687 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003688};
3689
3690
Johan Hedberg03811012010-12-08 00:21:06 +02003691int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3692{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003693 void *buf;
3694 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003695 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003696 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003697 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003698 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003699 int err;
3700
3701 BT_DBG("got %zu bytes", msglen);
3702
3703 if (msglen < sizeof(*hdr))
3704 return -EINVAL;
3705
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003706 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003707 if (!buf)
3708 return -ENOMEM;
3709
3710 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3711 err = -EFAULT;
3712 goto done;
3713 }
3714
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003715 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003716 opcode = __le16_to_cpu(hdr->opcode);
3717 index = __le16_to_cpu(hdr->index);
3718 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003719
3720 if (len != msglen - sizeof(*hdr)) {
3721 err = -EINVAL;
3722 goto done;
3723 }
3724
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003725 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003726 hdev = hci_dev_get(index);
3727 if (!hdev) {
3728 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003729 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003730 goto done;
3731 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003732
3733 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3734 err = cmd_status(sk, index, opcode,
3735 MGMT_STATUS_INVALID_INDEX);
3736 goto done;
3737 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003738 }
3739
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003740 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003741 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003742 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003743 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003744 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003745 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003746 }
3747
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003748 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003749 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003750 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003751 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003752 goto done;
3753 }
3754
Johan Hedbergbe22b542012-03-01 22:24:41 +02003755 handler = &mgmt_handlers[opcode];
3756
3757 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003758 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003759 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003760 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003761 goto done;
3762 }
3763
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003764 if (hdev)
3765 mgmt_init_hdev(sk, hdev);
3766
3767 cp = buf + sizeof(*hdr);
3768
Johan Hedbergbe22b542012-03-01 22:24:41 +02003769 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003770 if (err < 0)
3771 goto done;
3772
Johan Hedberg03811012010-12-08 00:21:06 +02003773 err = msglen;
3774
3775done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003776 if (hdev)
3777 hci_dev_put(hdev);
3778
Johan Hedberg03811012010-12-08 00:21:06 +02003779 kfree(buf);
3780 return err;
3781}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003782
Johan Hedberg744cf192011-11-08 20:40:14 +02003783int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003784{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003785 if (hdev->dev_type != HCI_BREDR)
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003786 return -ENOTSUPP;
3787
Johan Hedberg744cf192011-11-08 20:40:14 +02003788 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003789}
3790
Johan Hedberg744cf192011-11-08 20:40:14 +02003791int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003792{
Johan Hedberg5f159032012-03-02 03:13:19 +02003793 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003794
Marcel Holtmann1514b892013-10-06 08:25:01 -07003795 if (hdev->dev_type != HCI_BREDR)
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003796 return -ENOTSUPP;
3797
Johan Hedberg744cf192011-11-08 20:40:14 +02003798 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003799
Johan Hedberg744cf192011-11-08 20:40:14 +02003800 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003801}
3802
Johan Hedberg890ea892013-03-15 17:06:52 -05003803static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003804{
Johan Hedberg890ea892013-03-15 17:06:52 -05003805 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003806 u8 scan = 0;
3807
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003808 /* Ensure that fast connectable is disabled. This function will
3809 * not do anything if the page scan parameters are already what
3810 * they should be.
3811 */
3812 write_fast_connectable(req, false);
3813
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003814 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3815 scan |= SCAN_PAGE;
3816 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3817 scan |= SCAN_INQUIRY;
3818
Johan Hedberg890ea892013-03-15 17:06:52 -05003819 if (scan)
3820 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003821}
3822
Johan Hedberg229ab392013-03-15 17:06:53 -05003823static void powered_complete(struct hci_dev *hdev, u8 status)
3824{
3825 struct cmd_lookup match = { NULL, hdev };
3826
3827 BT_DBG("status 0x%02x", status);
3828
3829 hci_dev_lock(hdev);
3830
3831 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3832
3833 new_settings(hdev, match.sk);
3834
3835 hci_dev_unlock(hdev);
3836
3837 if (match.sk)
3838 sock_put(match.sk);
3839}
3840
Johan Hedberg70da6242013-03-15 17:06:51 -05003841static int powered_update_hci(struct hci_dev *hdev)
3842{
Johan Hedberg890ea892013-03-15 17:06:52 -05003843 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003844 u8 link_sec;
3845
Johan Hedberg890ea892013-03-15 17:06:52 -05003846 hci_req_init(&req, hdev);
3847
Johan Hedberg70da6242013-03-15 17:06:51 -05003848 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3849 !lmp_host_ssp_capable(hdev)) {
3850 u8 ssp = 1;
3851
Johan Hedberg890ea892013-03-15 17:06:52 -05003852 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003853 }
3854
Johan Hedbergc73eee92013-04-19 18:35:21 +03003855 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3856 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003857 struct hci_cp_write_le_host_supported cp;
3858
3859 cp.le = 1;
3860 cp.simul = lmp_le_br_capable(hdev);
3861
3862 /* Check first if we already have the right
3863 * host state (host features set)
3864 */
3865 if (cp.le != lmp_host_le_capable(hdev) ||
3866 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003867 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3868 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003869
3870 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3871 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003872 }
3873
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003874 if (lmp_le_capable(hdev)) {
3875 /* Set random address to static address if configured */
3876 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3877 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3878 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003879
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003880 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3881 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003882 }
3883
Johan Hedberg70da6242013-03-15 17:06:51 -05003884 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3885 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003886 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3887 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003888
3889 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003890 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3891 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003892 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003893 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003894 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003895 }
3896
Johan Hedberg229ab392013-03-15 17:06:53 -05003897 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003898}
3899
Johan Hedberg744cf192011-11-08 20:40:14 +02003900int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003901{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003902 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003903 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3904 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003905 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003906
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003907 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3908 return 0;
3909
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003910 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003911 if (powered_update_hci(hdev) == 0)
3912 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003913
Johan Hedberg229ab392013-03-15 17:06:53 -05003914 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3915 &match);
3916 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003917 }
3918
Johan Hedberg229ab392013-03-15 17:06:53 -05003919 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3920 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3921
3922 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3923 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3924 zero_cod, sizeof(zero_cod), NULL);
3925
3926new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003927 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003928
3929 if (match.sk)
3930 sock_put(match.sk);
3931
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003932 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003933}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003934
Johan Hedberg96570ff2013-05-29 09:51:29 +03003935int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3936{
3937 struct pending_cmd *cmd;
3938 u8 status;
3939
3940 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3941 if (!cmd)
3942 return -ENOENT;
3943
3944 if (err == -ERFKILL)
3945 status = MGMT_STATUS_RFKILLED;
3946 else
3947 status = MGMT_STATUS_FAILED;
3948
3949 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3950
3951 mgmt_pending_remove(cmd);
3952
3953 return err;
3954}
3955
Johan Hedberg744cf192011-11-08 20:40:14 +02003956int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003957{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003958 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003959 bool changed = false;
3960 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003961
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003962 if (discoverable) {
3963 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3964 changed = true;
3965 } else {
3966 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3967 changed = true;
3968 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003969
Johan Hedberged9b5f22012-02-21 20:47:06 +02003970 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003971 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003972
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003973 if (changed)
3974 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003975
Johan Hedberg73f22f62010-12-29 16:00:25 +02003976 if (match.sk)
3977 sock_put(match.sk);
3978
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003979 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003980}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003981
Johan Hedberg744cf192011-11-08 20:40:14 +02003982int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003983{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003984 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003985 bool changed = false;
3986 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003987
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003988 if (connectable) {
3989 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3990 changed = true;
3991 } else {
3992 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3993 changed = true;
3994 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003995
Johan Hedberg2b76f452013-03-15 17:07:04 -05003996 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003997
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003998 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003999 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004000
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004001 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004002}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004003
Johan Hedberg744cf192011-11-08 20:40:14 +02004004int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004005{
Johan Hedbergca69b792011-11-11 18:10:00 +02004006 u8 mgmt_err = mgmt_status(status);
4007
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004008 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004009 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004010 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004011
4012 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004013 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004014 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004015
4016 return 0;
4017}
4018
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004019int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4020 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004021{
Johan Hedberg86742e12011-11-07 23:13:38 +02004022 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004023
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004024 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004025
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004026 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004027 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004028 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004029 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004030 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004031 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004032
Johan Hedberg744cf192011-11-08 20:40:14 +02004033 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004034}
Johan Hedbergf7520542011-01-20 12:34:39 +02004035
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004036int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4037{
4038 struct mgmt_ev_new_long_term_key ev;
4039
4040 memset(&ev, 0, sizeof(ev));
4041
4042 ev.store_hint = persistent;
4043 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004044 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004045 ev.key.authenticated = key->authenticated;
4046 ev.key.enc_size = key->enc_size;
4047 ev.key.ediv = key->ediv;
4048
4049 if (key->type == HCI_SMP_LTK)
4050 ev.key.master = 1;
4051
4052 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4053 memcpy(ev.key.val, key->val, sizeof(key->val));
4054
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004055 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4056 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004057}
4058
Johan Hedbergafc747a2012-01-15 18:11:07 +02004059int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004060 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4061 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004062{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004063 char buf[512];
4064 struct mgmt_ev_device_connected *ev = (void *) buf;
4065 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004066
Johan Hedbergb644ba32012-01-17 21:48:47 +02004067 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004068 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004069
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004070 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004071
Johan Hedbergb644ba32012-01-17 21:48:47 +02004072 if (name_len > 0)
4073 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004074 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004075
4076 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004077 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004078 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004079
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004080 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004081
4082 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004083 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004084}
4085
Johan Hedberg8962ee72011-01-20 12:40:27 +02004086static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4087{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004088 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004089 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004090 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004091
Johan Hedberg88c3df12012-02-09 14:27:38 +02004092 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4093 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004094
Johan Hedbergaee9b212012-02-18 15:07:59 +02004095 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004096 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004097
4098 *sk = cmd->sk;
4099 sock_hold(*sk);
4100
Johan Hedberga664b5b2011-02-19 12:06:02 -03004101 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004102}
4103
Johan Hedberg124f6e32012-02-09 13:50:12 +02004104static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004105{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004106 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004107 struct mgmt_cp_unpair_device *cp = cmd->param;
4108 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004109
4110 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004111 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4112 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004113
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004114 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4115
Johan Hedbergaee9b212012-02-18 15:07:59 +02004116 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004117
4118 mgmt_pending_remove(cmd);
4119}
4120
Johan Hedbergafc747a2012-01-15 18:11:07 +02004121int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004122 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004123{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004124 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004125 struct sock *sk = NULL;
4126 int err;
4127
Johan Hedberg744cf192011-11-08 20:40:14 +02004128 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004129
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004130 bacpy(&ev.addr.bdaddr, bdaddr);
4131 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4132 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004133
Johan Hedbergafc747a2012-01-15 18:11:07 +02004134 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004135 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004136
4137 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004138 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004139
Johan Hedberg124f6e32012-02-09 13:50:12 +02004140 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004141 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004142
Johan Hedberg8962ee72011-01-20 12:40:27 +02004143 return err;
4144}
4145
Johan Hedberg88c3df12012-02-09 14:27:38 +02004146int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004147 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004148{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004149 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004150 struct pending_cmd *cmd;
4151 int err;
4152
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004153 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4154 hdev);
4155
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004156 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004157 if (!cmd)
4158 return -ENOENT;
4159
Johan Hedberg88c3df12012-02-09 14:27:38 +02004160 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004161 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004162
Johan Hedberg88c3df12012-02-09 14:27:38 +02004163 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004164 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004165
Johan Hedberga664b5b2011-02-19 12:06:02 -03004166 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004167
4168 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004169}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004170
Johan Hedberg48264f02011-11-09 13:58:58 +02004171int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004172 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004173{
4174 struct mgmt_ev_connect_failed ev;
4175
Johan Hedberg4c659c32011-11-07 23:13:39 +02004176 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004177 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004178 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004179
Johan Hedberg744cf192011-11-08 20:40:14 +02004180 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004181}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004182
Johan Hedberg744cf192011-11-08 20:40:14 +02004183int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004184{
4185 struct mgmt_ev_pin_code_request ev;
4186
Johan Hedbergd8457692012-02-17 14:24:57 +02004187 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004188 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004189 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004190
Johan Hedberg744cf192011-11-08 20:40:14 +02004191 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004192 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004193}
4194
Johan Hedberg744cf192011-11-08 20:40:14 +02004195int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004196 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004197{
4198 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004199 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004200 int err;
4201
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004202 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004203 if (!cmd)
4204 return -ENOENT;
4205
Johan Hedbergd8457692012-02-17 14:24:57 +02004206 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004207 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004208
Johan Hedbergaee9b212012-02-18 15:07:59 +02004209 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004210 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004211
Johan Hedberga664b5b2011-02-19 12:06:02 -03004212 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004213
4214 return err;
4215}
4216
Johan Hedberg744cf192011-11-08 20:40:14 +02004217int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004218 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004219{
4220 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004221 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004222 int err;
4223
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004224 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004225 if (!cmd)
4226 return -ENOENT;
4227
Johan Hedbergd8457692012-02-17 14:24:57 +02004228 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004229 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004230
Johan Hedbergaee9b212012-02-18 15:07:59 +02004231 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004232 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004233
Johan Hedberga664b5b2011-02-19 12:06:02 -03004234 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004235
4236 return err;
4237}
Johan Hedberga5c29682011-02-19 12:05:57 -03004238
Johan Hedberg744cf192011-11-08 20:40:14 +02004239int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004240 u8 link_type, u8 addr_type, __le32 value,
4241 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004242{
4243 struct mgmt_ev_user_confirm_request ev;
4244
Johan Hedberg744cf192011-11-08 20:40:14 +02004245 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004246
Johan Hedberg272d90d2012-02-09 15:26:12 +02004247 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004248 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004249 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004250 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004251
Johan Hedberg744cf192011-11-08 20:40:14 +02004252 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004253 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004254}
4255
Johan Hedberg272d90d2012-02-09 15:26:12 +02004256int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004257 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004258{
4259 struct mgmt_ev_user_passkey_request ev;
4260
4261 BT_DBG("%s", hdev->name);
4262
Johan Hedberg272d90d2012-02-09 15:26:12 +02004263 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004264 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004265
4266 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004267 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004268}
4269
Brian Gix0df4c182011-11-16 13:53:13 -08004270static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004271 u8 link_type, u8 addr_type, u8 status,
4272 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004273{
4274 struct pending_cmd *cmd;
4275 struct mgmt_rp_user_confirm_reply rp;
4276 int err;
4277
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004278 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004279 if (!cmd)
4280 return -ENOENT;
4281
Johan Hedberg272d90d2012-02-09 15:26:12 +02004282 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004283 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004284 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004285 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004286
Johan Hedberga664b5b2011-02-19 12:06:02 -03004287 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004288
4289 return err;
4290}
4291
Johan Hedberg744cf192011-11-08 20:40:14 +02004292int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004293 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004294{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004295 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004296 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004297}
4298
Johan Hedberg272d90d2012-02-09 15:26:12 +02004299int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004300 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004301{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004302 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004303 status,
4304 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004305}
Johan Hedberg2a611692011-02-19 12:06:00 -03004306
Brian Gix604086b2011-11-23 08:28:33 -08004307int mgmt_user_passkey_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)
Brian Gix604086b2011-11-23 08:28:33 -08004309{
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_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004312}
4313
Johan Hedberg272d90d2012-02-09 15:26:12 +02004314int mgmt_user_passkey_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)
Brian Gix604086b2011-11-23 08:28:33 -08004316{
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_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004320}
4321
Johan Hedberg92a25252012-09-06 18:39:26 +03004322int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4323 u8 link_type, u8 addr_type, u32 passkey,
4324 u8 entered)
4325{
4326 struct mgmt_ev_passkey_notify ev;
4327
4328 BT_DBG("%s", hdev->name);
4329
4330 bacpy(&ev.addr.bdaddr, bdaddr);
4331 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4332 ev.passkey = __cpu_to_le32(passkey);
4333 ev.entered = entered;
4334
4335 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4336}
4337
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004338int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004339 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004340{
4341 struct mgmt_ev_auth_failed ev;
4342
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004343 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004344 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004345 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004346
Johan Hedberg744cf192011-11-08 20:40:14 +02004347 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004348}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004349
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004350int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4351{
4352 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004353 bool changed = false;
4354 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004355
4356 if (status) {
4357 u8 mgmt_err = mgmt_status(status);
4358 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004359 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004360 return 0;
4361 }
4362
Johan Hedberg47990ea2012-02-22 11:58:37 +02004363 if (test_bit(HCI_AUTH, &hdev->flags)) {
4364 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4365 changed = true;
4366 } else {
4367 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4368 changed = true;
4369 }
4370
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004371 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004372 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004373
Johan Hedberg47990ea2012-02-22 11:58:37 +02004374 if (changed)
4375 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004376
4377 if (match.sk)
4378 sock_put(match.sk);
4379
4380 return err;
4381}
4382
Johan Hedberg890ea892013-03-15 17:06:52 -05004383static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004384{
Johan Hedberg890ea892013-03-15 17:06:52 -05004385 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004386 struct hci_cp_write_eir cp;
4387
Johan Hedberg976eb202012-10-24 21:12:01 +03004388 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004389 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004390
Johan Hedbergc80da272012-02-22 15:38:48 +02004391 memset(hdev->eir, 0, sizeof(hdev->eir));
4392
Johan Hedbergcacaf522012-02-21 00:52:42 +02004393 memset(&cp, 0, sizeof(cp));
4394
Johan Hedberg890ea892013-03-15 17:06:52 -05004395 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004396}
4397
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004398int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004399{
4400 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004401 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004402 bool changed = false;
4403 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004404
4405 if (status) {
4406 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004407
4408 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004409 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004410 err = new_settings(hdev, NULL);
4411
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004412 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4413 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004414
4415 return err;
4416 }
4417
4418 if (enable) {
4419 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4420 changed = true;
4421 } else {
4422 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4423 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004424 }
4425
4426 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4427
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004428 if (changed)
4429 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004430
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004431 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004432 sock_put(match.sk);
4433
Johan Hedberg890ea892013-03-15 17:06:52 -05004434 hci_req_init(&req, hdev);
4435
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004436 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004437 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004438 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004439 clear_eir(&req);
4440
4441 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004442
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004443 return err;
4444}
4445
Johan Hedberg92da6092013-03-15 17:06:55 -05004446static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004447{
4448 struct cmd_lookup *match = data;
4449
Johan Hedberg90e70452012-02-23 23:09:40 +02004450 if (match->sk == NULL) {
4451 match->sk = cmd->sk;
4452 sock_hold(match->sk);
4453 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004454}
4455
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004456int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004457 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004458{
Johan Hedberg90e70452012-02-23 23:09:40 +02004459 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4460 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004461
Johan Hedberg92da6092013-03-15 17:06:55 -05004462 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4463 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4464 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004465
4466 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004467 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4468 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004469
4470 if (match.sk)
4471 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004472
4473 return err;
4474}
4475
Johan Hedberg744cf192011-11-08 20:40:14 +02004476int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004477{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004478 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004479 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004480
Johan Hedberg13928972013-03-15 17:07:00 -05004481 if (status)
4482 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004483
4484 memset(&ev, 0, sizeof(ev));
4485 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004486 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004487
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004488 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004489 if (!cmd) {
4490 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004491
Johan Hedberg13928972013-03-15 17:07:00 -05004492 /* If this is a HCI command related to powering on the
4493 * HCI dev don't send any mgmt signals.
4494 */
4495 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4496 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004497 }
4498
Johan Hedberg13928972013-03-15 17:07:00 -05004499 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4500 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004501}
Szymon Jancc35938b2011-03-22 13:12:21 +01004502
Johan Hedberg744cf192011-11-08 20:40:14 +02004503int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004504 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004505{
4506 struct pending_cmd *cmd;
4507 int err;
4508
Johan Hedberg744cf192011-11-08 20:40:14 +02004509 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004510
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004511 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004512 if (!cmd)
4513 return -ENOENT;
4514
4515 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004516 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4517 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004518 } else {
4519 struct mgmt_rp_read_local_oob_data rp;
4520
4521 memcpy(rp.hash, hash, sizeof(rp.hash));
4522 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4523
Johan Hedberg744cf192011-11-08 20:40:14 +02004524 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004525 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4526 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004527 }
4528
4529 mgmt_pending_remove(cmd);
4530
4531 return err;
4532}
Johan Hedberge17acd42011-03-30 23:57:16 +03004533
Johan Hedberg48264f02011-11-09 13:58:58 +02004534int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004535 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4536 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004537{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004538 char buf[512];
4539 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004540 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004541
Andre Guedes12602d02013-04-30 15:29:40 -03004542 if (!hci_discovery_active(hdev))
4543 return -EPERM;
4544
Johan Hedberg1dc06092012-01-15 21:01:23 +02004545 /* Leave 5 bytes for a potential CoD field */
4546 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004547 return -EINVAL;
4548
Johan Hedberg1dc06092012-01-15 21:01:23 +02004549 memset(buf, 0, sizeof(buf));
4550
Johan Hedberge319d2e2012-01-15 19:51:59 +02004551 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004552 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004553 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004554 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304555 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004556 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304557 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004558
Johan Hedberg1dc06092012-01-15 21:01:23 +02004559 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004560 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004561
Johan Hedberg1dc06092012-01-15 21:01:23 +02004562 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4563 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004564 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004565
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004566 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004567 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004568
Johan Hedberge319d2e2012-01-15 19:51:59 +02004569 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004570}
Johan Hedberga88a9652011-03-30 13:18:12 +03004571
Johan Hedbergb644ba32012-01-17 21:48:47 +02004572int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004573 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004574{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004575 struct mgmt_ev_device_found *ev;
4576 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4577 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004578
Johan Hedbergb644ba32012-01-17 21:48:47 +02004579 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004580
Johan Hedbergb644ba32012-01-17 21:48:47 +02004581 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004582
Johan Hedbergb644ba32012-01-17 21:48:47 +02004583 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004584 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004585 ev->rssi = rssi;
4586
4587 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004588 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004589
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004590 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004591
Johan Hedberg053c7e02012-02-04 00:06:00 +02004592 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004593 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004594}
Johan Hedberg314b2382011-04-27 10:29:57 -04004595
Johan Hedberg744cf192011-11-08 20:40:14 +02004596int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004597{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004598 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004599 struct pending_cmd *cmd;
4600
Andre Guedes343fb142011-11-22 17:14:19 -03004601 BT_DBG("%s discovering %u", hdev->name, discovering);
4602
Johan Hedberg164a6e72011-11-01 17:06:44 +02004603 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004604 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004605 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004606 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004607
4608 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004609 u8 type = hdev->discovery.type;
4610
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004611 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4612 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004613 mgmt_pending_remove(cmd);
4614 }
4615
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004616 memset(&ev, 0, sizeof(ev));
4617 ev.type = hdev->discovery.type;
4618 ev.discovering = discovering;
4619
4620 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004621}
Antti Julku5e762442011-08-25 16:48:02 +03004622
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004623int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004624{
4625 struct pending_cmd *cmd;
4626 struct mgmt_ev_device_blocked ev;
4627
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004628 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004629
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004630 bacpy(&ev.addr.bdaddr, bdaddr);
4631 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004632
Johan Hedberg744cf192011-11-08 20:40:14 +02004633 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004634 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004635}
4636
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004637int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004638{
4639 struct pending_cmd *cmd;
4640 struct mgmt_ev_device_unblocked ev;
4641
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004642 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004643
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004644 bacpy(&ev.addr.bdaddr, bdaddr);
4645 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004646
Johan Hedberg744cf192011-11-08 20:40:14 +02004647 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004648 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004649}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004650
4651static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4652{
4653 BT_DBG("%s status %u", hdev->name, status);
4654
4655 /* Clear the advertising mgmt setting if we failed to re-enable it */
4656 if (status) {
4657 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004658 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004659 }
4660}
4661
4662void mgmt_reenable_advertising(struct hci_dev *hdev)
4663{
4664 struct hci_request req;
4665
4666 if (hdev->conn_hash.le_num)
4667 return;
4668
4669 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4670 return;
4671
4672 hci_req_init(&req, hdev);
4673 enable_advertising(&req);
4674
4675 /* If this fails we have no option but to let user space know
4676 * that we've disabled advertising.
4677 */
4678 if (hci_req_run(&req, adv_enable_complete) < 0) {
4679 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004680 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004681 }
4682}