blob: 83866848a21582d0a7aa724ab89bfd54d1267b42 [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
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300185bool mgmt_valid_hdev(struct hci_dev *hdev)
186{
187 return hdev->dev_type == HCI_BREDR;
188}
189
Johan Hedbergca69b792011-11-11 18:10:00 +0200190static u8 mgmt_status(u8 hci_status)
191{
192 if (hci_status < ARRAY_SIZE(mgmt_status_table))
193 return mgmt_status_table[hci_status];
194
195 return MGMT_STATUS_FAILED;
196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200199{
200 struct sk_buff *skb;
201 struct mgmt_hdr *hdr;
202 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300203 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204
Szymon Janc34eb5252011-02-28 14:10:08 +0100205 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200206
Andre Guedes790eff42012-06-07 19:05:46 -0300207 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200208 if (!skb)
209 return -ENOMEM;
210
211 hdr = (void *) skb_put(skb, sizeof(*hdr));
212
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530213 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100214 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200215 hdr->len = cpu_to_le16(sizeof(*ev));
216
217 ev = (void *) skb_put(skb, sizeof(*ev));
218 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200219 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300221 err = sock_queue_rcv_skb(sk, skb);
222 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 kfree_skb(skb);
224
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300225 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200226}
227
Johan Hedbergaee9b212012-02-18 15:07:59 +0200228static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300229 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200230{
231 struct sk_buff *skb;
232 struct mgmt_hdr *hdr;
233 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200235
236 BT_DBG("sock %p", sk);
237
Andre Guedes790eff42012-06-07 19:05:46 -0300238 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200239 if (!skb)
240 return -ENOMEM;
241
242 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200243
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530244 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100245 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
Johan Hedberga38528f2011-01-22 06:46:43 +0200248 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200249 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200250 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100251
252 if (rp)
253 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200254
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300255 err = sock_queue_rcv_skb(sk, skb);
256 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200257 kfree_skb(skb);
258
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100259 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200260}
261
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300262static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
263 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200264{
265 struct mgmt_rp_read_version rp;
266
267 BT_DBG("sock %p", sk);
268
269 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200270 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200271
Johan Hedbergaee9b212012-02-18 15:07:59 +0200272 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200274}
275
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300276static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
277 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200278{
279 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200280 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
281 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200282 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283 size_t rp_size;
284 int i, err;
285
286 BT_DBG("sock %p", sk);
287
288 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
289
290 rp = kmalloc(rp_size, GFP_KERNEL);
291 if (!rp)
292 return -ENOMEM;
293
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200294 rp->num_commands = __constant_cpu_to_le16(num_commands);
295 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200296
297 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
298 put_unaligned_le16(mgmt_commands[i], opcode);
299
300 for (i = 0; i < num_events; i++, opcode++)
301 put_unaligned_le16(mgmt_events[i], opcode);
302
Johan Hedbergaee9b212012-02-18 15:07:59 +0200303 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300304 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305 kfree(rp);
306
307 return err;
308}
309
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300310static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
311 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200314 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200315 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300317 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318
319 BT_DBG("sock %p", sk);
320
321 read_lock(&hci_dev_list_lock);
322
323 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300324 list_for_each_entry(d, &hci_dev_list, list) {
325 if (!mgmt_valid_hdev(d))
326 continue;
327
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 count++;
329 }
330
Johan Hedberga38528f2011-01-22 06:46:43 +0200331 rp_len = sizeof(*rp) + (2 * count);
332 rp = kmalloc(rp_len, GFP_ATOMIC);
333 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100334 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200335 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100336 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200337
Johan Hedberg476e44c2012-10-19 20:10:46 +0300338 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200339 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200340 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200341 continue;
342
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700343 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
344 continue;
345
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300346 if (!mgmt_valid_hdev(d))
347 continue;
348
Johan Hedberg476e44c2012-10-19 20:10:46 +0300349 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 BT_DBG("Added hci%u", d->id);
351 }
352
Johan Hedberg476e44c2012-10-19 20:10:46 +0300353 rp->num_controllers = cpu_to_le16(count);
354 rp_len = sizeof(*rp) + (2 * count);
355
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356 read_unlock(&hci_dev_list_lock);
357
Johan Hedbergaee9b212012-02-18 15:07:59 +0200358 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300359 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
Johan Hedberga38528f2011-01-22 06:46:43 +0200361 kfree(rp);
362
363 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364}
365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200367{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200369
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200371 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200372
Andre Guedes9a1a1992012-07-24 15:03:48 -0300373 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200375
Andre Guedesed3fa312012-07-24 15:03:46 -0300376 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300377 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500378 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
379 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300380 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200381 settings |= MGMT_SETTING_BREDR;
382 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700384 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100385
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300386 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200387 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300388 settings |= MGMT_SETTING_ADVERTISING;
389 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391 return settings;
392}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200393
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394static u32 get_current_settings(struct hci_dev *hdev)
395{
396 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200397
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200398 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500404 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
405 settings |= MGMT_SETTING_FAST_CONNECTABLE;
406
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200407 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_DISCOVERABLE;
409
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200410 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_PAIRABLE;
412
Johan Hedberg56f87902013-10-02 13:43:13 +0300413 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_BREDR;
415
Johan Hedberg06199cf2012-02-22 16:37:11 +0200416 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg47990ea2012-02-22 11:58:37 +0200419 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200421
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200422 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200424
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200425 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
426 settings |= MGMT_SETTING_HS;
427
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200428 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300429 settings |= MGMT_SETTING_ADVERTISING;
430
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200431 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200432}
433
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300434#define PNP_INFO_SVCLASS_ID 0x1200
435
Johan Hedberg213202e2013-01-27 00:31:33 +0200436static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
437{
438 u8 *ptr = data, *uuids_start = NULL;
439 struct bt_uuid *uuid;
440
441 if (len < 4)
442 return ptr;
443
444 list_for_each_entry(uuid, &hdev->uuids, list) {
445 u16 uuid16;
446
447 if (uuid->size != 16)
448 continue;
449
450 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
451 if (uuid16 < 0x1100)
452 continue;
453
454 if (uuid16 == PNP_INFO_SVCLASS_ID)
455 continue;
456
457 if (!uuids_start) {
458 uuids_start = ptr;
459 uuids_start[0] = 1;
460 uuids_start[1] = EIR_UUID16_ALL;
461 ptr += 2;
462 }
463
464 /* Stop if not enough space to put next UUID */
465 if ((ptr - data) + sizeof(u16) > len) {
466 uuids_start[1] = EIR_UUID16_SOME;
467 break;
468 }
469
470 *ptr++ = (uuid16 & 0x00ff);
471 *ptr++ = (uuid16 & 0xff00) >> 8;
472 uuids_start[0] += sizeof(uuid16);
473 }
474
475 return ptr;
476}
477
Johan Hedbergcdf19632013-01-27 00:31:34 +0200478static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
479{
480 u8 *ptr = data, *uuids_start = NULL;
481 struct bt_uuid *uuid;
482
483 if (len < 6)
484 return ptr;
485
486 list_for_each_entry(uuid, &hdev->uuids, list) {
487 if (uuid->size != 32)
488 continue;
489
490 if (!uuids_start) {
491 uuids_start = ptr;
492 uuids_start[0] = 1;
493 uuids_start[1] = EIR_UUID32_ALL;
494 ptr += 2;
495 }
496
497 /* Stop if not enough space to put next UUID */
498 if ((ptr - data) + sizeof(u32) > len) {
499 uuids_start[1] = EIR_UUID32_SOME;
500 break;
501 }
502
503 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
504 ptr += sizeof(u32);
505 uuids_start[0] += sizeof(u32);
506 }
507
508 return ptr;
509}
510
Johan Hedbergc00d5752013-01-27 00:31:35 +0200511static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
512{
513 u8 *ptr = data, *uuids_start = NULL;
514 struct bt_uuid *uuid;
515
516 if (len < 18)
517 return ptr;
518
519 list_for_each_entry(uuid, &hdev->uuids, list) {
520 if (uuid->size != 128)
521 continue;
522
523 if (!uuids_start) {
524 uuids_start = ptr;
525 uuids_start[0] = 1;
526 uuids_start[1] = EIR_UUID128_ALL;
527 ptr += 2;
528 }
529
530 /* Stop if not enough space to put next UUID */
531 if ((ptr - data) + 16 > len) {
532 uuids_start[1] = EIR_UUID128_SOME;
533 break;
534 }
535
536 memcpy(ptr, uuid->uuid, 16);
537 ptr += 16;
538 uuids_start[0] += 16;
539 }
540
541 return ptr;
542}
543
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300544static void create_eir(struct hci_dev *hdev, u8 *data)
545{
546 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300547 size_t name_len;
548
549 name_len = strlen(hdev->dev_name);
550
551 if (name_len > 0) {
552 /* EIR Data type */
553 if (name_len > 48) {
554 name_len = 48;
555 ptr[1] = EIR_NAME_SHORT;
556 } else
557 ptr[1] = EIR_NAME_COMPLETE;
558
559 /* EIR Data length */
560 ptr[0] = name_len + 1;
561
562 memcpy(ptr + 2, hdev->dev_name, name_len);
563
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 ptr += (name_len + 2);
565 }
566
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100567 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700568 ptr[0] = 2;
569 ptr[1] = EIR_TX_POWER;
570 ptr[2] = (u8) hdev->inq_tx_power;
571
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700572 ptr += 3;
573 }
574
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700575 if (hdev->devid_source > 0) {
576 ptr[0] = 9;
577 ptr[1] = EIR_DEVICE_ID;
578
579 put_unaligned_le16(hdev->devid_source, ptr + 2);
580 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
581 put_unaligned_le16(hdev->devid_product, ptr + 6);
582 put_unaligned_le16(hdev->devid_version, ptr + 8);
583
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700584 ptr += 10;
585 }
586
Johan Hedberg213202e2013-01-27 00:31:33 +0200587 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200588 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200589 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300590}
591
Johan Hedberg890ea892013-03-15 17:06:52 -0500592static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300593{
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595 struct hci_cp_write_eir cp;
596
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200597 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500598 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200599
Johan Hedberg976eb202012-10-24 21:12:01 +0300600 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500601 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300602
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200603 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500604 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300605
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200606 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500607 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608
609 memset(&cp, 0, sizeof(cp));
610
611 create_eir(hdev, cp.data);
612
613 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500614 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300615
616 memcpy(hdev->eir, cp.data, sizeof(cp.data));
617
Johan Hedberg890ea892013-03-15 17:06:52 -0500618 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300619}
620
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621static u8 get_service_classes(struct hci_dev *hdev)
622{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300623 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624 u8 val = 0;
625
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300626 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628
629 return val;
630}
631
Johan Hedberg890ea892013-03-15 17:06:52 -0500632static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200633{
Johan Hedberg890ea892013-03-15 17:06:52 -0500634 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200635 u8 cod[3];
636
637 BT_DBG("%s", hdev->name);
638
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200639 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500640 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200641
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200642 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500643 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200644
645 cod[0] = hdev->minor_class;
646 cod[1] = hdev->major_class;
647 cod[2] = get_service_classes(hdev);
648
649 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500650 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200651
Johan Hedberg890ea892013-03-15 17:06:52 -0500652 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200653}
654
Johan Hedberg7d785252011-12-15 00:47:39 +0200655static void service_cache_off(struct work_struct *work)
656{
657 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300658 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500659 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200660
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200661 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200662 return;
663
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 hci_req_init(&req, hdev);
665
Johan Hedberg7d785252011-12-15 00:47:39 +0200666 hci_dev_lock(hdev);
667
Johan Hedberg890ea892013-03-15 17:06:52 -0500668 update_eir(&req);
669 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200670
671 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500672
673 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200674}
675
Johan Hedberg6a919082012-02-28 06:17:26 +0200676static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200677{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200678 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200679 return;
680
Johan Hedberg4f87da82012-03-02 19:55:56 +0200681 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200682
Johan Hedberg4f87da82012-03-02 19:55:56 +0200683 /* Non-mgmt controlled devices get this bit set
684 * implicitly so that pairing works for them, however
685 * for mgmt we require user-space to explicitly enable
686 * it
687 */
688 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200689}
690
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200691static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200693{
694 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200696 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200697
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300698 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200699
Johan Hedberg03811012010-12-08 00:21:06 +0200700 memset(&rp, 0, sizeof(rp));
701
Johan Hedberg03811012010-12-08 00:21:06 +0200702 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200703
704 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200705 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200706
707 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
708 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
709
710 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200711
712 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200713 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300715 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200716
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200717 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300718 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200719}
720
721static void mgmt_pending_free(struct pending_cmd *cmd)
722{
723 sock_put(cmd->sk);
724 kfree(cmd->param);
725 kfree(cmd);
726}
727
728static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300729 struct hci_dev *hdev, void *data,
730 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200731{
732 struct pending_cmd *cmd;
733
Andre Guedes12b94562012-06-07 19:05:45 -0300734 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200735 if (!cmd)
736 return NULL;
737
738 cmd->opcode = opcode;
739 cmd->index = hdev->id;
740
Andre Guedes12b94562012-06-07 19:05:45 -0300741 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 if (!cmd->param) {
743 kfree(cmd);
744 return NULL;
745 }
746
747 if (data)
748 memcpy(cmd->param, data, len);
749
750 cmd->sk = sk;
751 sock_hold(sk);
752
753 list_add(&cmd->list, &hdev->mgmt_pending);
754
755 return cmd;
756}
757
758static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300759 void (*cb)(struct pending_cmd *cmd,
760 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300761 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200762{
Andre Guedesa3d09352013-02-01 11:21:30 -0300763 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200764
Andre Guedesa3d09352013-02-01 11:21:30 -0300765 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200766 if (opcode > 0 && cmd->opcode != opcode)
767 continue;
768
769 cb(cmd, data);
770 }
771}
772
773static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
774{
775 struct pending_cmd *cmd;
776
777 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
778 if (cmd->opcode == opcode)
779 return cmd;
780 }
781
782 return NULL;
783}
784
785static void mgmt_pending_remove(struct pending_cmd *cmd)
786{
787 list_del(&cmd->list);
788 mgmt_pending_free(cmd);
789}
790
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200792{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200793 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200794
Johan Hedbergaee9b212012-02-18 15:07:59 +0200795 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200797}
798
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200799static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300800 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200801{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300802 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200803 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200804 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200806 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedberga7e80f22013-01-09 16:05:19 +0200808 if (cp->val != 0x00 && cp->val != 0x01)
809 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
810 MGMT_STATUS_INVALID_PARAMS);
811
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300812 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200813
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300814 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
815 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
816 MGMT_STATUS_BUSY);
817 goto failed;
818 }
819
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100820 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
821 cancel_delayed_work(&hdev->power_off);
822
823 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200824 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
825 data, len);
826 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100827 goto failed;
828 }
829 }
830
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200831 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200832 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200833 goto failed;
834 }
835
Johan Hedberg03811012010-12-08 00:21:06 +0200836 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
837 if (!cmd) {
838 err = -ENOMEM;
839 goto failed;
840 }
841
842 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200843 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200844 else
Johan Hedberg19202572013-01-14 22:33:51 +0200845 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200846
847 err = 0;
848
849failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300850 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200851 return err;
852}
853
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300854static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
855 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200856{
857 struct sk_buff *skb;
858 struct mgmt_hdr *hdr;
859
Andre Guedes790eff42012-06-07 19:05:46 -0300860 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200861 if (!skb)
862 return -ENOMEM;
863
864 hdr = (void *) skb_put(skb, sizeof(*hdr));
865 hdr->opcode = cpu_to_le16(event);
866 if (hdev)
867 hdr->index = cpu_to_le16(hdev->id);
868 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530869 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200870 hdr->len = cpu_to_le16(data_len);
871
872 if (data)
873 memcpy(skb_put(skb, data_len), data, data_len);
874
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100875 /* Time stamp */
876 __net_timestamp(skb);
877
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200878 hci_send_to_control(skb, skip_sk);
879 kfree_skb(skb);
880
881 return 0;
882}
883
884static int new_settings(struct hci_dev *hdev, struct sock *skip)
885{
886 __le32 ev;
887
888 ev = cpu_to_le32(get_current_settings(hdev));
889
890 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
891}
892
Johan Hedbergd2f5a192013-10-05 12:01:05 +0200893int mgmt_new_settings(struct hci_dev *hdev)
894{
895 return new_settings(hdev, NULL);
896}
897
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300898struct cmd_lookup {
899 struct sock *sk;
900 struct hci_dev *hdev;
901 u8 mgmt_status;
902};
903
904static void settings_rsp(struct pending_cmd *cmd, void *data)
905{
906 struct cmd_lookup *match = data;
907
908 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
909
910 list_del(&cmd->list);
911
912 if (match->sk == NULL) {
913 match->sk = cmd->sk;
914 sock_hold(match->sk);
915 }
916
917 mgmt_pending_free(cmd);
918}
919
920static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
921{
922 u8 *status = data;
923
924 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
925 mgmt_pending_remove(cmd);
926}
927
Johan Hedberge6fe7982013-10-02 15:45:22 +0300928static u8 mgmt_bredr_support(struct hci_dev *hdev)
929{
930 if (!lmp_bredr_capable(hdev))
931 return MGMT_STATUS_NOT_SUPPORTED;
932 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
933 return MGMT_STATUS_REJECTED;
934 else
935 return MGMT_STATUS_SUCCESS;
936}
937
938static u8 mgmt_le_support(struct hci_dev *hdev)
939{
940 if (!lmp_le_capable(hdev))
941 return MGMT_STATUS_NOT_SUPPORTED;
942 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
943 return MGMT_STATUS_REJECTED;
944 else
945 return MGMT_STATUS_SUCCESS;
946}
947
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200948static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300949 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200950{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300951 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200952 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200953 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300954 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200955 int err;
956
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200957 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200958
Johan Hedberge6fe7982013-10-02 15:45:22 +0300959 status = mgmt_bredr_support(hdev);
960 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300961 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300962 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300963
Johan Hedberga7e80f22013-01-09 16:05:19 +0200964 if (cp->val != 0x00 && cp->val != 0x01)
965 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
966 MGMT_STATUS_INVALID_PARAMS);
967
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700968 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100969 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200970 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300971 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200972
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300973 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 if (!hdev_is_powered(hdev) && timeout > 0) {
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_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200978 goto failed;
979 }
980
981 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300982 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200983 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300984 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200985 goto failed;
986 }
987
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200988 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200989 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300990 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200991 goto failed;
992 }
993
994 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200995 bool changed = false;
996
997 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
998 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
999 changed = true;
1000 }
1001
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001002 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001003 if (err < 0)
1004 goto failed;
1005
1006 if (changed)
1007 err = new_settings(hdev, sk);
1008
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001009 goto failed;
1010 }
1011
1012 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001013 if (hdev->discov_timeout > 0) {
1014 cancel_delayed_work(&hdev->discov_off);
1015 hdev->discov_timeout = 0;
1016 }
1017
1018 if (cp->val && timeout > 0) {
1019 hdev->discov_timeout = timeout;
1020 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1021 msecs_to_jiffies(hdev->discov_timeout * 1000));
1022 }
1023
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001024 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001025 goto failed;
1026 }
1027
1028 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1029 if (!cmd) {
1030 err = -ENOMEM;
1031 goto failed;
1032 }
1033
1034 scan = SCAN_PAGE;
1035
1036 if (cp->val)
1037 scan |= SCAN_INQUIRY;
1038 else
1039 cancel_delayed_work(&hdev->discov_off);
1040
1041 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1042 if (err < 0)
1043 mgmt_pending_remove(cmd);
1044
Johan Hedberg03811012010-12-08 00:21:06 +02001045 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001046 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001047
1048failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001049 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001050 return err;
1051}
1052
Johan Hedberg406d7802013-03-15 17:07:09 -05001053static void write_fast_connectable(struct hci_request *req, bool enable)
1054{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001055 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001056 struct hci_cp_write_page_scan_activity acp;
1057 u8 type;
1058
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001059 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1060 return;
1061
Johan Hedberg406d7802013-03-15 17:07:09 -05001062 if (enable) {
1063 type = PAGE_SCAN_TYPE_INTERLACED;
1064
1065 /* 160 msec page scan interval */
1066 acp.interval = __constant_cpu_to_le16(0x0100);
1067 } else {
1068 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1069
1070 /* default 1.28 sec page scan */
1071 acp.interval = __constant_cpu_to_le16(0x0800);
1072 }
1073
1074 acp.window = __constant_cpu_to_le16(0x0012);
1075
Johan Hedbergbd98b992013-03-15 17:07:13 -05001076 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1077 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1078 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1079 sizeof(acp), &acp);
1080
1081 if (hdev->page_scan_type != type)
1082 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001083}
1084
Johan Hedberg2b76f452013-03-15 17:07:04 -05001085static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1086{
1087 struct pending_cmd *cmd;
1088
1089 BT_DBG("status 0x%02x", status);
1090
1091 hci_dev_lock(hdev);
1092
1093 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1094 if (!cmd)
1095 goto unlock;
1096
1097 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1098
1099 mgmt_pending_remove(cmd);
1100
1101unlock:
1102 hci_dev_unlock(hdev);
1103}
1104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001105static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001106 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001107{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001108 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001109 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001110 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001111 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001112 int err;
1113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001114 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001115
Johan Hedberge6fe7982013-10-02 15:45:22 +03001116 status = mgmt_bredr_support(hdev);
1117 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001118 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001119 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001120
Johan Hedberga7e80f22013-01-09 16:05:19 +02001121 if (cp->val != 0x00 && cp->val != 0x01)
1122 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1123 MGMT_STATUS_INVALID_PARAMS);
1124
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001125 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001126
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001127 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001128 bool changed = false;
1129
1130 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1131 changed = true;
1132
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001133 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001134 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001135 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001136 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1137 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1138 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001139
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001140 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001141 if (err < 0)
1142 goto failed;
1143
1144 if (changed)
1145 err = new_settings(hdev, sk);
1146
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001147 goto failed;
1148 }
1149
1150 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001151 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001152 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001153 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001154 goto failed;
1155 }
1156
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001157 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001158 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001159 goto failed;
1160 }
1161
1162 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1163 if (!cmd) {
1164 err = -ENOMEM;
1165 goto failed;
1166 }
1167
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001168 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001169 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001170 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001171 scan = 0;
1172
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001173 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001174 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001175 cancel_delayed_work(&hdev->discov_off);
1176 }
1177
Johan Hedberg2b76f452013-03-15 17:07:04 -05001178 hci_req_init(&req, hdev);
1179
1180 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1181
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001182 /* If we're going from non-connectable to connectable or
1183 * vice-versa when fast connectable is enabled ensure that fast
1184 * connectable gets disabled. write_fast_connectable won't do
1185 * anything if the page scan parameters are already what they
1186 * should be.
1187 */
1188 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001189 write_fast_connectable(&req, false);
1190
Johan Hedberg2b76f452013-03-15 17:07:04 -05001191 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192 if (err < 0)
1193 mgmt_pending_remove(cmd);
1194
1195failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001196 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001197 return err;
1198}
1199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001201 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001202{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001203 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001204 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001205
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001206 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207
Johan Hedberga7e80f22013-01-09 16:05:19 +02001208 if (cp->val != 0x00 && cp->val != 0x01)
1209 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1210 MGMT_STATUS_INVALID_PARAMS);
1211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001212 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
1214 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001215 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001216 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001217 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001218
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001219 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001220 if (err < 0)
1221 goto failed;
1222
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001223 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001224
1225failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001226 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001227 return err;
1228}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001229
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001230static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1231 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001232{
1233 struct mgmt_mode *cp = data;
1234 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001235 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001236 int err;
1237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001238 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001239
Johan Hedberge6fe7982013-10-02 15:45:22 +03001240 status = mgmt_bredr_support(hdev);
1241 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001242 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001243 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001244
Johan Hedberga7e80f22013-01-09 16:05:19 +02001245 if (cp->val != 0x00 && cp->val != 0x01)
1246 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1247 MGMT_STATUS_INVALID_PARAMS);
1248
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001249 hci_dev_lock(hdev);
1250
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001251 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001252 bool changed = false;
1253
1254 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001255 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001256 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1257 changed = true;
1258 }
1259
1260 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1261 if (err < 0)
1262 goto failed;
1263
1264 if (changed)
1265 err = new_settings(hdev, sk);
1266
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001267 goto failed;
1268 }
1269
1270 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001271 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001272 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001273 goto failed;
1274 }
1275
1276 val = !!cp->val;
1277
1278 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1279 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1280 goto failed;
1281 }
1282
1283 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1284 if (!cmd) {
1285 err = -ENOMEM;
1286 goto failed;
1287 }
1288
1289 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1290 if (err < 0) {
1291 mgmt_pending_remove(cmd);
1292 goto failed;
1293 }
1294
1295failed:
1296 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001297 return err;
1298}
1299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001300static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001301{
1302 struct mgmt_mode *cp = data;
1303 struct pending_cmd *cmd;
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001304 u8 val, status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001305 int err;
1306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001307 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001308
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001309 status = mgmt_bredr_support(hdev);
1310 if (status)
1311 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1312
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001313 if (!lmp_ssp_capable(hdev))
1314 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1315 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001316
Johan Hedberga7e80f22013-01-09 16:05:19 +02001317 if (cp->val != 0x00 && cp->val != 0x01)
1318 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1319 MGMT_STATUS_INVALID_PARAMS);
1320
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001321 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001322
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001323 val = !!cp->val;
1324
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001325 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001326 bool changed = false;
1327
1328 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1329 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1330 changed = true;
1331 }
1332
1333 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1334 if (err < 0)
1335 goto failed;
1336
1337 if (changed)
1338 err = new_settings(hdev, sk);
1339
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001340 goto failed;
1341 }
1342
1343 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001344 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1345 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001346 goto failed;
1347 }
1348
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001349 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1350 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1351 goto failed;
1352 }
1353
1354 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1355 if (!cmd) {
1356 err = -ENOMEM;
1357 goto failed;
1358 }
1359
1360 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1361 if (err < 0) {
1362 mgmt_pending_remove(cmd);
1363 goto failed;
1364 }
1365
1366failed:
1367 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001368 return err;
1369}
1370
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001371static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001372{
1373 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001374 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001375 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001376 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001377
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001378 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001379
Johan Hedberge6fe7982013-10-02 15:45:22 +03001380 status = mgmt_bredr_support(hdev);
1381 if (status)
1382 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001383
Johan Hedberga7e80f22013-01-09 16:05:19 +02001384 if (cp->val != 0x00 && cp->val != 0x01)
1385 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1386 MGMT_STATUS_INVALID_PARAMS);
1387
Marcel Holtmannee392692013-10-01 22:59:23 -07001388 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001389
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001390 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001391 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001392 } else {
1393 if (hdev_is_powered(hdev)) {
1394 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1395 MGMT_STATUS_REJECTED);
1396 goto unlock;
1397 }
1398
Marcel Holtmannee392692013-10-01 22:59:23 -07001399 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001400 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001401
1402 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1403 if (err < 0)
1404 goto unlock;
1405
1406 if (changed)
1407 err = new_settings(hdev, sk);
1408
1409unlock:
1410 hci_dev_unlock(hdev);
1411 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001412}
1413
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001414static void enable_advertising(struct hci_request *req)
1415{
1416 u8 adv = 0x01;
1417
1418 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
1419}
1420
1421static void disable_advertising(struct hci_request *req)
1422{
1423 u8 adv = 0x00;
1424
1425 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
1426}
1427
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001428static void le_enable_complete(struct hci_dev *hdev, u8 status)
1429{
1430 struct cmd_lookup match = { NULL, hdev };
1431
1432 if (status) {
1433 u8 mgmt_err = mgmt_status(status);
1434
1435 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1436 &mgmt_err);
1437 return;
1438 }
1439
1440 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1441
1442 new_settings(hdev, match.sk);
1443
1444 if (match.sk)
1445 sock_put(match.sk);
1446}
1447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001448static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001449{
1450 struct mgmt_mode *cp = data;
1451 struct hci_cp_write_le_host_supported hci_cp;
1452 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001453 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001454 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001455 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001456
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001457 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001458
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001459 if (!lmp_le_capable(hdev))
1460 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1461 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001462
Johan Hedberga7e80f22013-01-09 16:05:19 +02001463 if (cp->val != 0x00 && cp->val != 0x01)
1464 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1465 MGMT_STATUS_INVALID_PARAMS);
1466
Johan Hedbergc73eee92013-04-19 18:35:21 +03001467 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001468 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001469 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1470 MGMT_STATUS_REJECTED);
1471
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001472 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001473
1474 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001475 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001476
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001477 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001478 bool changed = false;
1479
1480 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1481 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1482 changed = true;
1483 }
1484
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001485 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1486 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001487 changed = true;
1488 }
1489
Johan Hedberg06199cf2012-02-22 16:37:11 +02001490 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1491 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001492 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001493
1494 if (changed)
1495 err = new_settings(hdev, sk);
1496
Johan Hedberg1de028c2012-02-29 19:55:35 -08001497 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001498 }
1499
Johan Hedberg4375f102013-09-25 13:26:10 +03001500 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1501 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001502 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001503 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001504 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001505 }
1506
1507 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1508 if (!cmd) {
1509 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001510 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001511 }
1512
1513 memset(&hci_cp, 0, sizeof(hci_cp));
1514
1515 if (val) {
1516 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001517 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001518 }
1519
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001520 hci_req_init(&req, hdev);
1521
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001522 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1523 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001524
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001525 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1526 &hci_cp);
1527
1528 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301529 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001530 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001531
Johan Hedberg1de028c2012-02-29 19:55:35 -08001532unlock:
1533 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001534 return err;
1535}
1536
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001537/* This is a helper function to test for pending mgmt commands that can
1538 * cause CoD or EIR HCI commands. We can only allow one such pending
1539 * mgmt command at a time since otherwise we cannot easily track what
1540 * the current values are, will be, and based on that calculate if a new
1541 * HCI command needs to be sent and if yes with what value.
1542 */
1543static bool pending_eir_or_class(struct hci_dev *hdev)
1544{
1545 struct pending_cmd *cmd;
1546
1547 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1548 switch (cmd->opcode) {
1549 case MGMT_OP_ADD_UUID:
1550 case MGMT_OP_REMOVE_UUID:
1551 case MGMT_OP_SET_DEV_CLASS:
1552 case MGMT_OP_SET_POWERED:
1553 return true;
1554 }
1555 }
1556
1557 return false;
1558}
1559
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001560static const u8 bluetooth_base_uuid[] = {
1561 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1562 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1563};
1564
1565static u8 get_uuid_size(const u8 *uuid)
1566{
1567 u32 val;
1568
1569 if (memcmp(uuid, bluetooth_base_uuid, 12))
1570 return 128;
1571
1572 val = get_unaligned_le32(&uuid[12]);
1573 if (val > 0xffff)
1574 return 32;
1575
1576 return 16;
1577}
1578
Johan Hedberg92da6092013-03-15 17:06:55 -05001579static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1580{
1581 struct pending_cmd *cmd;
1582
1583 hci_dev_lock(hdev);
1584
1585 cmd = mgmt_pending_find(mgmt_op, hdev);
1586 if (!cmd)
1587 goto unlock;
1588
1589 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1590 hdev->dev_class, 3);
1591
1592 mgmt_pending_remove(cmd);
1593
1594unlock:
1595 hci_dev_unlock(hdev);
1596}
1597
1598static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1599{
1600 BT_DBG("status 0x%02x", status);
1601
1602 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1603}
1604
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001605static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001606{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001607 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001608 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001609 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001610 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001611 int err;
1612
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001613 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001614
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001615 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001616
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001617 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001618 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001619 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001620 goto failed;
1621 }
1622
Andre Guedes92c4c202012-06-07 19:05:44 -03001623 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001624 if (!uuid) {
1625 err = -ENOMEM;
1626 goto failed;
1627 }
1628
1629 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001630 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001631 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001632
Johan Hedbergde66aa62013-01-27 00:31:27 +02001633 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001634
Johan Hedberg890ea892013-03-15 17:06:52 -05001635 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001636
Johan Hedberg890ea892013-03-15 17:06:52 -05001637 update_class(&req);
1638 update_eir(&req);
1639
Johan Hedberg92da6092013-03-15 17:06:55 -05001640 err = hci_req_run(&req, add_uuid_complete);
1641 if (err < 0) {
1642 if (err != -ENODATA)
1643 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001644
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001645 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001646 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001647 goto failed;
1648 }
1649
1650 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001651 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001652 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001653 goto failed;
1654 }
1655
1656 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001657
1658failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001659 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001660 return err;
1661}
1662
Johan Hedberg24b78d02012-02-23 23:24:30 +02001663static bool enable_service_cache(struct hci_dev *hdev)
1664{
1665 if (!hdev_is_powered(hdev))
1666 return false;
1667
1668 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001669 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1670 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001671 return true;
1672 }
1673
1674 return false;
1675}
1676
Johan Hedberg92da6092013-03-15 17:06:55 -05001677static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1678{
1679 BT_DBG("status 0x%02x", status);
1680
1681 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1682}
1683
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001684static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001685 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001686{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001687 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001688 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001689 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001690 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 -05001691 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001692 int err, found;
1693
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001694 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001695
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001696 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001697
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001698 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001699 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001700 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001701 goto unlock;
1702 }
1703
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001704 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1705 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001706
Johan Hedberg24b78d02012-02-23 23:24:30 +02001707 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001708 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001709 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001710 goto unlock;
1711 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001712
Johan Hedberg9246a862012-02-23 21:33:16 +02001713 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001714 }
1715
1716 found = 0;
1717
Johan Hedberg056341c2013-01-27 00:31:30 +02001718 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001719 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1720 continue;
1721
1722 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001723 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001724 found++;
1725 }
1726
1727 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001728 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001729 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001730 goto unlock;
1731 }
1732
Johan Hedberg9246a862012-02-23 21:33:16 +02001733update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001734 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001735
Johan Hedberg890ea892013-03-15 17:06:52 -05001736 update_class(&req);
1737 update_eir(&req);
1738
Johan Hedberg92da6092013-03-15 17:06:55 -05001739 err = hci_req_run(&req, remove_uuid_complete);
1740 if (err < 0) {
1741 if (err != -ENODATA)
1742 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001743
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001744 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001745 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001746 goto unlock;
1747 }
1748
1749 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001750 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001751 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001752 goto unlock;
1753 }
1754
1755 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001756
1757unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001758 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001759 return err;
1760}
1761
Johan Hedberg92da6092013-03-15 17:06:55 -05001762static void set_class_complete(struct hci_dev *hdev, u8 status)
1763{
1764 BT_DBG("status 0x%02x", status);
1765
1766 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1767}
1768
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001769static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001770 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001771{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001772 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001773 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001774 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001775 int err;
1776
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001777 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001778
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001779 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001780 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1781 MGMT_STATUS_NOT_SUPPORTED);
1782
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001783 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001784
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001785 if (pending_eir_or_class(hdev)) {
1786 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1787 MGMT_STATUS_BUSY);
1788 goto unlock;
1789 }
1790
1791 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1792 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1793 MGMT_STATUS_INVALID_PARAMS);
1794 goto unlock;
1795 }
1796
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001797 hdev->major_class = cp->major;
1798 hdev->minor_class = cp->minor;
1799
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001800 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001801 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001802 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001803 goto unlock;
1804 }
1805
Johan Hedberg890ea892013-03-15 17:06:52 -05001806 hci_req_init(&req, hdev);
1807
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001808 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001809 hci_dev_unlock(hdev);
1810 cancel_delayed_work_sync(&hdev->service_cache);
1811 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001812 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001813 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001814
Johan Hedberg890ea892013-03-15 17:06:52 -05001815 update_class(&req);
1816
Johan Hedberg92da6092013-03-15 17:06:55 -05001817 err = hci_req_run(&req, set_class_complete);
1818 if (err < 0) {
1819 if (err != -ENODATA)
1820 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001821
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001822 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001823 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001824 goto unlock;
1825 }
1826
1827 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001828 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001829 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001830 goto unlock;
1831 }
1832
1833 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001834
Johan Hedbergb5235a62012-02-21 14:32:24 +02001835unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001836 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001837 return err;
1838}
1839
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001840static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001841 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001842{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001843 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001844 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001845 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001846
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001847 BT_DBG("request for %s", hdev->name);
1848
1849 if (!lmp_bredr_capable(hdev))
1850 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1851 MGMT_STATUS_NOT_SUPPORTED);
1852
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001853 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001854
Johan Hedberg86742e12011-11-07 23:13:38 +02001855 expected_len = sizeof(*cp) + key_count *
1856 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001857 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001858 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001859 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001860 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001861 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001862 }
1863
Johan Hedberg4ae14302013-01-20 14:27:13 +02001864 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1865 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1866 MGMT_STATUS_INVALID_PARAMS);
1867
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001868 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001869 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001870
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001871 for (i = 0; i < key_count; i++) {
1872 struct mgmt_link_key_info *key = &cp->keys[i];
1873
1874 if (key->addr.type != BDADDR_BREDR)
1875 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1876 MGMT_STATUS_INVALID_PARAMS);
1877 }
1878
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001879 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001880
1881 hci_link_keys_clear(hdev);
1882
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001883 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001884 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001885 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001886 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001887
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001888 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001889 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001890
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001891 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001892 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001893 }
1894
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001895 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001896
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001897 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001898
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001899 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001900}
1901
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001902static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001903 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001904{
1905 struct mgmt_ev_device_unpaired ev;
1906
1907 bacpy(&ev.addr.bdaddr, bdaddr);
1908 ev.addr.type = addr_type;
1909
1910 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001911 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001912}
1913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001915 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001916{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001917 struct mgmt_cp_unpair_device *cp = data;
1918 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001919 struct hci_cp_disconnect dc;
1920 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001921 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001922 int err;
1923
Johan Hedberga8a1d192011-11-10 15:54:38 +02001924 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001925 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1926 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001927
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001928 if (!bdaddr_type_is_valid(cp->addr.type))
1929 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1930 MGMT_STATUS_INVALID_PARAMS,
1931 &rp, sizeof(rp));
1932
Johan Hedberg118da702013-01-20 14:27:20 +02001933 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1934 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1935 MGMT_STATUS_INVALID_PARAMS,
1936 &rp, sizeof(rp));
1937
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001938 hci_dev_lock(hdev);
1939
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001940 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001941 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001942 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001943 goto unlock;
1944 }
1945
Andre Guedes591f47f2012-04-24 21:02:49 -03001946 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001947 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1948 else
1949 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001950
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001951 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001952 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001953 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001954 goto unlock;
1955 }
1956
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001957 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001958 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001959 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001960 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001961 else
1962 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001963 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001964 } else {
1965 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001966 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001967
Johan Hedberga8a1d192011-11-10 15:54:38 +02001968 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001969 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001970 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001971 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001972 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001973 }
1974
Johan Hedberg124f6e32012-02-09 13:50:12 +02001975 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001976 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001977 if (!cmd) {
1978 err = -ENOMEM;
1979 goto unlock;
1980 }
1981
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001982 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001983 dc.reason = 0x13; /* Remote User Terminated Connection */
1984 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1985 if (err < 0)
1986 mgmt_pending_remove(cmd);
1987
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001988unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001989 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001990 return err;
1991}
1992
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001993static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001994 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001995{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001996 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001997 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001998 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001999 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002000 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002001 int err;
2002
2003 BT_DBG("");
2004
Johan Hedberg06a63b12013-01-20 14:27:21 +02002005 memset(&rp, 0, sizeof(rp));
2006 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2007 rp.addr.type = cp->addr.type;
2008
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002009 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002010 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2011 MGMT_STATUS_INVALID_PARAMS,
2012 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002013
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002014 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002015
2016 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002017 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2018 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002019 goto failed;
2020 }
2021
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002022 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002023 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2024 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002025 goto failed;
2026 }
2027
Andre Guedes591f47f2012-04-24 21:02:49 -03002028 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002029 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2030 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002031 else
2032 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002033
Vishal Agarwalf9607272012-06-13 05:32:43 +05302034 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002035 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2036 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002037 goto failed;
2038 }
2039
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002040 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002041 if (!cmd) {
2042 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002043 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002044 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002045
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002046 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002047 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002048
2049 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2050 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002051 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002052
2053failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002054 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002055 return err;
2056}
2057
Andre Guedes57c14772012-04-24 21:02:50 -03002058static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002059{
2060 switch (link_type) {
2061 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002062 switch (addr_type) {
2063 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002064 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002065
Johan Hedberg48264f02011-11-09 13:58:58 +02002066 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002067 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002068 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002069 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002070
Johan Hedberg4c659c32011-11-07 23:13:39 +02002071 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002072 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002073 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002074 }
2075}
2076
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002077static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2078 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002079{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002080 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002081 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002082 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002083 int err;
2084 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002085
2086 BT_DBG("");
2087
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002088 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002089
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002090 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002091 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002092 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002093 goto unlock;
2094 }
2095
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002096 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002097 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2098 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002099 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002100 }
2101
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002102 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002103 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002104 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002105 err = -ENOMEM;
2106 goto unlock;
2107 }
2108
Johan Hedberg2784eb42011-01-21 13:56:35 +02002109 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002110 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002111 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2112 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002113 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002114 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002115 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002116 continue;
2117 i++;
2118 }
2119
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002120 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002121
Johan Hedberg4c659c32011-11-07 23:13:39 +02002122 /* Recalculate length in case of filtered SCO connections, etc */
2123 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002125 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002126 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002127
Johan Hedberga38528f2011-01-22 06:46:43 +02002128 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002129
2130unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002131 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002132 return err;
2133}
2134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002135static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002136 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002137{
2138 struct pending_cmd *cmd;
2139 int err;
2140
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002141 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002142 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002143 if (!cmd)
2144 return -ENOMEM;
2145
Johan Hedbergd8457692012-02-17 14:24:57 +02002146 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002147 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002148 if (err < 0)
2149 mgmt_pending_remove(cmd);
2150
2151 return err;
2152}
2153
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002154static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002155 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002156{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002157 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002158 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002159 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002160 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002161 int err;
2162
2163 BT_DBG("");
2164
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002165 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002166
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002167 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002168 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002169 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002170 goto failed;
2171 }
2172
Johan Hedbergd8457692012-02-17 14:24:57 +02002173 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002174 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002175 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002177 goto failed;
2178 }
2179
2180 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002181 struct mgmt_cp_pin_code_neg_reply ncp;
2182
2183 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002184
2185 BT_ERR("PIN code is not 16 bytes long");
2186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002187 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002188 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002189 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002191
2192 goto failed;
2193 }
2194
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002195 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002196 if (!cmd) {
2197 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002198 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002199 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002200
Johan Hedbergd8457692012-02-17 14:24:57 +02002201 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002202 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002203 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002204
2205 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2206 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002207 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002208
2209failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002210 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002211 return err;
2212}
2213
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002214static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2215 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002216{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002217 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002218
2219 BT_DBG("");
2220
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002221 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002222
2223 hdev->io_capability = cp->io_capability;
2224
2225 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002226 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002227
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002228 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002229
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002230 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2231 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002232}
2233
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002234static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002235{
2236 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002237 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002238
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002239 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002240 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2241 continue;
2242
Johan Hedberge9a416b2011-02-19 12:05:56 -03002243 if (cmd->user_data != conn)
2244 continue;
2245
2246 return cmd;
2247 }
2248
2249 return NULL;
2250}
2251
2252static void pairing_complete(struct pending_cmd *cmd, u8 status)
2253{
2254 struct mgmt_rp_pair_device rp;
2255 struct hci_conn *conn = cmd->user_data;
2256
Johan Hedbergba4e5642011-11-11 00:07:34 +02002257 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002258 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002259
Johan Hedbergaee9b212012-02-18 15:07:59 +02002260 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002261 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002262
2263 /* So we don't get further callbacks for this connection */
2264 conn->connect_cfm_cb = NULL;
2265 conn->security_cfm_cb = NULL;
2266 conn->disconn_cfm_cb = NULL;
2267
David Herrmann76a68ba2013-04-06 20:28:37 +02002268 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002269
Johan Hedberga664b5b2011-02-19 12:06:02 -03002270 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002271}
2272
2273static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2274{
2275 struct pending_cmd *cmd;
2276
2277 BT_DBG("status %u", status);
2278
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002279 cmd = find_pairing(conn);
2280 if (!cmd)
2281 BT_DBG("Unable to find a pending command");
2282 else
Johan Hedberge2113262012-02-18 15:20:03 +02002283 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002284}
2285
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302286static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2287{
2288 struct pending_cmd *cmd;
2289
2290 BT_DBG("status %u", status);
2291
2292 if (!status)
2293 return;
2294
2295 cmd = find_pairing(conn);
2296 if (!cmd)
2297 BT_DBG("Unable to find a pending command");
2298 else
2299 pairing_complete(cmd, mgmt_status(status));
2300}
2301
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002302static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002303 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002304{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002305 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002306 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002307 struct pending_cmd *cmd;
2308 u8 sec_level, auth_type;
2309 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002310 int err;
2311
2312 BT_DBG("");
2313
Szymon Jancf950a30e2013-01-18 12:48:07 +01002314 memset(&rp, 0, sizeof(rp));
2315 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2316 rp.addr.type = cp->addr.type;
2317
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002318 if (!bdaddr_type_is_valid(cp->addr.type))
2319 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2320 MGMT_STATUS_INVALID_PARAMS,
2321 &rp, sizeof(rp));
2322
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002323 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002324
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002325 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002326 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2327 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002328 goto unlock;
2329 }
2330
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002331 sec_level = BT_SECURITY_MEDIUM;
2332 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002333 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002334 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002335 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002336
Andre Guedes591f47f2012-04-24 21:02:49 -03002337 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002338 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2339 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002340 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002341 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2342 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002343
Ville Tervo30e76272011-02-22 16:10:53 -03002344 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002345 int status;
2346
2347 if (PTR_ERR(conn) == -EBUSY)
2348 status = MGMT_STATUS_BUSY;
2349 else
2350 status = MGMT_STATUS_CONNECT_FAILED;
2351
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002352 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002353 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002354 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002355 goto unlock;
2356 }
2357
2358 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002359 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002361 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002362 goto unlock;
2363 }
2364
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002365 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002366 if (!cmd) {
2367 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002368 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002369 goto unlock;
2370 }
2371
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002372 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002373 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002374 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302375 else
2376 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002377
Johan Hedberge9a416b2011-02-19 12:05:56 -03002378 conn->security_cfm_cb = pairing_complete_cb;
2379 conn->disconn_cfm_cb = pairing_complete_cb;
2380 conn->io_capability = cp->io_cap;
2381 cmd->user_data = conn;
2382
2383 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002384 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002385 pairing_complete(cmd, 0);
2386
2387 err = 0;
2388
2389unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002390 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002391 return err;
2392}
2393
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002394static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2395 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002396{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002397 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002398 struct pending_cmd *cmd;
2399 struct hci_conn *conn;
2400 int err;
2401
2402 BT_DBG("");
2403
Johan Hedberg28424702012-02-02 04:02:29 +02002404 hci_dev_lock(hdev);
2405
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002406 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002407 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002408 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002409 goto unlock;
2410 }
2411
Johan Hedberg28424702012-02-02 04:02:29 +02002412 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2413 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002414 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002415 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002416 goto unlock;
2417 }
2418
2419 conn = cmd->user_data;
2420
2421 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002422 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002423 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002424 goto unlock;
2425 }
2426
2427 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2428
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002429 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002430 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002431unlock:
2432 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002433 return err;
2434}
2435
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002436static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002437 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002438 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002439{
Johan Hedberga5c29682011-02-19 12:05:57 -03002440 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002441 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002442 int err;
2443
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002444 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002445
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002446 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002447 err = cmd_complete(sk, hdev->id, mgmt_op,
2448 MGMT_STATUS_NOT_POWERED, addr,
2449 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002450 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002451 }
2452
Johan Hedberg1707c602013-03-15 17:07:15 -05002453 if (addr->type == BDADDR_BREDR)
2454 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002455 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002456 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002457
Johan Hedberg272d90d2012-02-09 15:26:12 +02002458 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002459 err = cmd_complete(sk, hdev->id, mgmt_op,
2460 MGMT_STATUS_NOT_CONNECTED, addr,
2461 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002462 goto done;
2463 }
2464
Johan Hedberg1707c602013-03-15 17:07:15 -05002465 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002466 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002467 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002468
Brian Gix5fe57d92011-12-21 16:12:13 -08002469 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002470 err = cmd_complete(sk, hdev->id, mgmt_op,
2471 MGMT_STATUS_SUCCESS, addr,
2472 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002473 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002474 err = cmd_complete(sk, hdev->id, mgmt_op,
2475 MGMT_STATUS_FAILED, addr,
2476 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002477
Brian Gix47c15e22011-11-16 13:53:14 -08002478 goto done;
2479 }
2480
Johan Hedberg1707c602013-03-15 17:07:15 -05002481 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002482 if (!cmd) {
2483 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002484 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002485 }
2486
Brian Gix0df4c182011-11-16 13:53:13 -08002487 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002488 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2489 struct hci_cp_user_passkey_reply cp;
2490
Johan Hedberg1707c602013-03-15 17:07:15 -05002491 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002492 cp.passkey = passkey;
2493 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2494 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002495 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2496 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002497
Johan Hedberga664b5b2011-02-19 12:06:02 -03002498 if (err < 0)
2499 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002500
Brian Gix0df4c182011-11-16 13:53:13 -08002501done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002502 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002503 return err;
2504}
2505
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302506static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2507 void *data, u16 len)
2508{
2509 struct mgmt_cp_pin_code_neg_reply *cp = data;
2510
2511 BT_DBG("");
2512
Johan Hedberg1707c602013-03-15 17:07:15 -05002513 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302514 MGMT_OP_PIN_CODE_NEG_REPLY,
2515 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2516}
2517
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002518static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2519 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002520{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002521 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002522
2523 BT_DBG("");
2524
2525 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002526 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002527 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002528
Johan Hedberg1707c602013-03-15 17:07:15 -05002529 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002530 MGMT_OP_USER_CONFIRM_REPLY,
2531 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002532}
2533
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002534static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002535 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002536{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002537 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002538
2539 BT_DBG("");
2540
Johan Hedberg1707c602013-03-15 17:07:15 -05002541 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002542 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2543 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002544}
2545
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002546static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2547 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002548{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002549 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002550
2551 BT_DBG("");
2552
Johan Hedberg1707c602013-03-15 17:07:15 -05002553 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002554 MGMT_OP_USER_PASSKEY_REPLY,
2555 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002556}
2557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002558static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002559 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002560{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002561 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002562
2563 BT_DBG("");
2564
Johan Hedberg1707c602013-03-15 17:07:15 -05002565 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2567 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002568}
2569
Johan Hedberg13928972013-03-15 17:07:00 -05002570static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002571{
Johan Hedberg13928972013-03-15 17:07:00 -05002572 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002573 struct hci_cp_write_local_name cp;
2574
Johan Hedberg13928972013-03-15 17:07:00 -05002575 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002576
Johan Hedberg890ea892013-03-15 17:06:52 -05002577 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002578}
2579
Johan Hedberg13928972013-03-15 17:07:00 -05002580static void set_name_complete(struct hci_dev *hdev, u8 status)
2581{
2582 struct mgmt_cp_set_local_name *cp;
2583 struct pending_cmd *cmd;
2584
2585 BT_DBG("status 0x%02x", status);
2586
2587 hci_dev_lock(hdev);
2588
2589 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2590 if (!cmd)
2591 goto unlock;
2592
2593 cp = cmd->param;
2594
2595 if (status)
2596 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2597 mgmt_status(status));
2598 else
2599 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2600 cp, sizeof(*cp));
2601
2602 mgmt_pending_remove(cmd);
2603
2604unlock:
2605 hci_dev_unlock(hdev);
2606}
2607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002608static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002609 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002610{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002611 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002612 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002613 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002614 int err;
2615
2616 BT_DBG("");
2617
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002618 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002619
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002620 /* If the old values are the same as the new ones just return a
2621 * direct command complete event.
2622 */
2623 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2624 !memcmp(hdev->short_name, cp->short_name,
2625 sizeof(hdev->short_name))) {
2626 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2627 data, len);
2628 goto failed;
2629 }
2630
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002631 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002632
Johan Hedbergb5235a62012-02-21 14:32:24 +02002633 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002634 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002635
2636 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002637 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002638 if (err < 0)
2639 goto failed;
2640
2641 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002642 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002643
Johan Hedbergb5235a62012-02-21 14:32:24 +02002644 goto failed;
2645 }
2646
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002647 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002648 if (!cmd) {
2649 err = -ENOMEM;
2650 goto failed;
2651 }
2652
Johan Hedberg13928972013-03-15 17:07:00 -05002653 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2654
Johan Hedberg890ea892013-03-15 17:06:52 -05002655 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002656
2657 if (lmp_bredr_capable(hdev)) {
2658 update_name(&req);
2659 update_eir(&req);
2660 }
2661
2662 if (lmp_le_capable(hdev))
2663 hci_update_ad(&req);
2664
Johan Hedberg13928972013-03-15 17:07:00 -05002665 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002666 if (err < 0)
2667 mgmt_pending_remove(cmd);
2668
2669failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002670 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002671 return err;
2672}
2673
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002674static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002675 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002676{
Szymon Jancc35938b2011-03-22 13:12:21 +01002677 struct pending_cmd *cmd;
2678 int err;
2679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002680 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002681
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002682 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002683
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002684 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002685 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002686 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002687 goto unlock;
2688 }
2689
Andre Guedes9a1a1992012-07-24 15:03:48 -03002690 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002691 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002692 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002693 goto unlock;
2694 }
2695
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002696 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002697 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002698 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002699 goto unlock;
2700 }
2701
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002702 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002703 if (!cmd) {
2704 err = -ENOMEM;
2705 goto unlock;
2706 }
2707
2708 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2709 if (err < 0)
2710 mgmt_pending_remove(cmd);
2711
2712unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002713 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002714 return err;
2715}
2716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002717static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002718 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002719{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002720 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002721 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002722 int err;
2723
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002724 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002725
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002726 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002727
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002728 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002729 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002730 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002731 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002732 else
Szymon Janca6785be2012-12-13 15:11:21 +01002733 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002735 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002736 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002737
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002738 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002739 return err;
2740}
2741
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002742static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002743 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002744{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002745 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002746 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002747 int err;
2748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002749 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002750
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002751 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002752
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002753 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002754 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002755 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002756 else
Szymon Janca6785be2012-12-13 15:11:21 +01002757 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002758
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002759 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002760 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002761
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002762 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002763 return err;
2764}
2765
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002766static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2767{
2768 struct pending_cmd *cmd;
2769 u8 type;
2770 int err;
2771
2772 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2773
2774 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2775 if (!cmd)
2776 return -ENOENT;
2777
2778 type = hdev->discovery.type;
2779
2780 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2781 &type, sizeof(type));
2782 mgmt_pending_remove(cmd);
2783
2784 return err;
2785}
2786
Andre Guedes7c307722013-04-30 15:29:28 -03002787static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2788{
2789 BT_DBG("status %d", status);
2790
2791 if (status) {
2792 hci_dev_lock(hdev);
2793 mgmt_start_discovery_failed(hdev, status);
2794 hci_dev_unlock(hdev);
2795 return;
2796 }
2797
2798 hci_dev_lock(hdev);
2799 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2800 hci_dev_unlock(hdev);
2801
2802 switch (hdev->discovery.type) {
2803 case DISCOV_TYPE_LE:
2804 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002805 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002806 break;
2807
2808 case DISCOV_TYPE_INTERLEAVED:
2809 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002810 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002811 break;
2812
2813 case DISCOV_TYPE_BREDR:
2814 break;
2815
2816 default:
2817 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2818 }
2819}
2820
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002821static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002822 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002823{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002824 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002825 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002826 struct hci_cp_le_set_scan_param param_cp;
2827 struct hci_cp_le_set_scan_enable enable_cp;
2828 struct hci_cp_inquiry inq_cp;
2829 struct hci_request req;
2830 /* General inquiry access code (GIAC) */
2831 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002832 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002833 int err;
2834
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002835 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002836
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002837 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002838
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002839 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002840 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002841 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002842 goto failed;
2843 }
2844
Andre Guedes642be6c2012-03-21 00:03:37 -03002845 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2846 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2847 MGMT_STATUS_BUSY);
2848 goto failed;
2849 }
2850
Johan Hedbergff9ef572012-01-04 14:23:45 +02002851 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002852 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002853 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002854 goto failed;
2855 }
2856
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002857 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002858 if (!cmd) {
2859 err = -ENOMEM;
2860 goto failed;
2861 }
2862
Andre Guedes4aab14e2012-02-17 20:39:36 -03002863 hdev->discovery.type = cp->type;
2864
Andre Guedes7c307722013-04-30 15:29:28 -03002865 hci_req_init(&req, hdev);
2866
Andre Guedes4aab14e2012-02-17 20:39:36 -03002867 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002868 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002869 status = mgmt_bredr_support(hdev);
2870 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002871 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002872 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002873 mgmt_pending_remove(cmd);
2874 goto failed;
2875 }
2876
Andre Guedes7c307722013-04-30 15:29:28 -03002877 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2878 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2879 MGMT_STATUS_BUSY);
2880 mgmt_pending_remove(cmd);
2881 goto failed;
2882 }
2883
2884 hci_inquiry_cache_flush(hdev);
2885
2886 memset(&inq_cp, 0, sizeof(inq_cp));
2887 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002888 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002889 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002890 break;
2891
2892 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002893 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002894 status = mgmt_le_support(hdev);
2895 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002896 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002897 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002898 mgmt_pending_remove(cmd);
2899 goto failed;
2900 }
2901
Andre Guedes7c307722013-04-30 15:29:28 -03002902 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002903 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002904 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2905 MGMT_STATUS_NOT_SUPPORTED);
2906 mgmt_pending_remove(cmd);
2907 goto failed;
2908 }
2909
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002910 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002911 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2912 MGMT_STATUS_REJECTED);
2913 mgmt_pending_remove(cmd);
2914 goto failed;
2915 }
2916
2917 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2918 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2919 MGMT_STATUS_BUSY);
2920 mgmt_pending_remove(cmd);
2921 goto failed;
2922 }
2923
2924 memset(&param_cp, 0, sizeof(param_cp));
2925 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002926 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2927 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002928 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2929 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2930 else
2931 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002932 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2933 &param_cp);
2934
2935 memset(&enable_cp, 0, sizeof(enable_cp));
2936 enable_cp.enable = LE_SCAN_ENABLE;
2937 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2938 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2939 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002940 break;
2941
Andre Guedesf39799f2012-02-17 20:39:35 -03002942 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002943 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2944 MGMT_STATUS_INVALID_PARAMS);
2945 mgmt_pending_remove(cmd);
2946 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002947 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002948
Andre Guedes7c307722013-04-30 15:29:28 -03002949 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002950 if (err < 0)
2951 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002952 else
2953 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002954
2955failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002956 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002957 return err;
2958}
2959
Andre Guedes1183fdc2013-04-30 15:29:35 -03002960static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2961{
2962 struct pending_cmd *cmd;
2963 int err;
2964
2965 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2966 if (!cmd)
2967 return -ENOENT;
2968
2969 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2970 &hdev->discovery.type, sizeof(hdev->discovery.type));
2971 mgmt_pending_remove(cmd);
2972
2973 return err;
2974}
2975
Andre Guedes0e05bba2013-04-30 15:29:33 -03002976static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2977{
2978 BT_DBG("status %d", status);
2979
2980 hci_dev_lock(hdev);
2981
2982 if (status) {
2983 mgmt_stop_discovery_failed(hdev, status);
2984 goto unlock;
2985 }
2986
2987 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2988
2989unlock:
2990 hci_dev_unlock(hdev);
2991}
2992
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002993static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002994 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002995{
Johan Hedbergd9306502012-02-20 23:25:18 +02002996 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002997 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002998 struct hci_cp_remote_name_req_cancel cp;
2999 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003000 struct hci_request req;
3001 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003002 int err;
3003
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003004 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003005
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003006 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003007
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003008 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003009 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003010 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3011 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003012 goto unlock;
3013 }
3014
3015 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003016 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003017 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3018 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003019 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003020 }
3021
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003022 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003023 if (!cmd) {
3024 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003025 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003026 }
3027
Andre Guedes0e05bba2013-04-30 15:29:33 -03003028 hci_req_init(&req, hdev);
3029
Andre Guedese0d9727e2012-03-20 15:15:36 -03003030 switch (hdev->discovery.state) {
3031 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003032 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3033 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3034 } else {
3035 cancel_delayed_work(&hdev->le_scan_disable);
3036
3037 memset(&enable_cp, 0, sizeof(enable_cp));
3038 enable_cp.enable = LE_SCAN_DISABLE;
3039 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3040 sizeof(enable_cp), &enable_cp);
3041 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003042
Andre Guedese0d9727e2012-03-20 15:15:36 -03003043 break;
3044
3045 case DISCOVERY_RESOLVING:
3046 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003047 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003048 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003049 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003050 err = cmd_complete(sk, hdev->id,
3051 MGMT_OP_STOP_DISCOVERY, 0,
3052 &mgmt_cp->type,
3053 sizeof(mgmt_cp->type));
3054 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3055 goto unlock;
3056 }
3057
3058 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003059 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3060 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003061
3062 break;
3063
3064 default:
3065 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003066
3067 mgmt_pending_remove(cmd);
3068 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3069 MGMT_STATUS_FAILED, &mgmt_cp->type,
3070 sizeof(mgmt_cp->type));
3071 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003072 }
3073
Andre Guedes0e05bba2013-04-30 15:29:33 -03003074 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003075 if (err < 0)
3076 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003077 else
3078 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003079
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003080unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003081 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003082 return err;
3083}
3084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003085static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003086 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003087{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003088 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003089 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003090 int err;
3091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003092 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003093
Johan Hedberg561aafb2012-01-04 13:31:59 +02003094 hci_dev_lock(hdev);
3095
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003096 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003097 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003098 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003099 goto failed;
3100 }
3101
Johan Hedberga198e7b2012-02-17 14:27:06 +02003102 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003103 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003104 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003106 goto failed;
3107 }
3108
3109 if (cp->name_known) {
3110 e->name_state = NAME_KNOWN;
3111 list_del(&e->list);
3112 } else {
3113 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003114 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003115 }
3116
Johan Hedberge3846622013-01-09 15:29:33 +02003117 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3118 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003119
3120failed:
3121 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003122 return err;
3123}
3124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003125static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003126 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003127{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003128 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003129 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003130 int err;
3131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003132 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003133
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003134 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003135 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3136 MGMT_STATUS_INVALID_PARAMS,
3137 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003138
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003139 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003140
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003141 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003142 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003143 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003144 else
Szymon Janca6785be2012-12-13 15:11:21 +01003145 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003147 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003148 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003149
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003150 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003151
3152 return err;
3153}
3154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003155static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003156 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003157{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003158 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003159 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003160 int err;
3161
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003162 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003163
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003164 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003165 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3166 MGMT_STATUS_INVALID_PARAMS,
3167 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003168
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003169 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003170
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003171 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003172 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003173 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003174 else
Szymon Janca6785be2012-12-13 15:11:21 +01003175 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003177 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003178 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003179
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003180 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003181
3182 return err;
3183}
3184
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003185static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3186 u16 len)
3187{
3188 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003189 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003190 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003191 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003192
3193 BT_DBG("%s", hdev->name);
3194
Szymon Jancc72d4b82012-03-16 16:02:57 +01003195 source = __le16_to_cpu(cp->source);
3196
3197 if (source > 0x0002)
3198 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3199 MGMT_STATUS_INVALID_PARAMS);
3200
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003201 hci_dev_lock(hdev);
3202
Szymon Jancc72d4b82012-03-16 16:02:57 +01003203 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003204 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3205 hdev->devid_product = __le16_to_cpu(cp->product);
3206 hdev->devid_version = __le16_to_cpu(cp->version);
3207
3208 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3209
Johan Hedberg890ea892013-03-15 17:06:52 -05003210 hci_req_init(&req, hdev);
3211 update_eir(&req);
3212 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003213
3214 hci_dev_unlock(hdev);
3215
3216 return err;
3217}
3218
Johan Hedberg4375f102013-09-25 13:26:10 +03003219static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3220{
3221 struct cmd_lookup match = { NULL, hdev };
3222
3223 if (status) {
3224 u8 mgmt_err = mgmt_status(status);
3225
3226 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3227 cmd_status_rsp, &mgmt_err);
3228 return;
3229 }
3230
3231 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3232 &match);
3233
3234 new_settings(hdev, match.sk);
3235
3236 if (match.sk)
3237 sock_put(match.sk);
3238}
3239
3240static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3241{
3242 struct mgmt_mode *cp = data;
3243 struct pending_cmd *cmd;
3244 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003245 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003246 int err;
3247
3248 BT_DBG("request for %s", hdev->name);
3249
Johan Hedberge6fe7982013-10-02 15:45:22 +03003250 status = mgmt_le_support(hdev);
3251 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003252 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003253 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003254
3255 if (cp->val != 0x00 && cp->val != 0x01)
3256 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3257 MGMT_STATUS_INVALID_PARAMS);
3258
3259 hci_dev_lock(hdev);
3260
3261 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003262 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003263
3264 if (!hdev_is_powered(hdev) || val == enabled) {
3265 bool changed = false;
3266
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003267 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3268 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003269 changed = true;
3270 }
3271
3272 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3273 if (err < 0)
3274 goto unlock;
3275
3276 if (changed)
3277 err = new_settings(hdev, sk);
3278
3279 goto unlock;
3280 }
3281
3282 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3283 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3284 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3285 MGMT_STATUS_BUSY);
3286 goto unlock;
3287 }
3288
3289 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3290 if (!cmd) {
3291 err = -ENOMEM;
3292 goto unlock;
3293 }
3294
3295 hci_req_init(&req, hdev);
3296
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003297 if (val)
3298 enable_advertising(&req);
3299 else
3300 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003301
3302 err = hci_req_run(&req, set_advertising_complete);
3303 if (err < 0)
3304 mgmt_pending_remove(cmd);
3305
3306unlock:
3307 hci_dev_unlock(hdev);
3308 return err;
3309}
3310
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003311static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3312 void *data, u16 len)
3313{
3314 struct mgmt_cp_set_static_address *cp = data;
3315 int err;
3316
3317 BT_DBG("%s", hdev->name);
3318
Marcel Holtmann62af4442013-10-02 22:10:32 -07003319 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003320 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003321 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003322
3323 if (hdev_is_powered(hdev))
3324 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3325 MGMT_STATUS_REJECTED);
3326
3327 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3328 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3329 return cmd_status(sk, hdev->id,
3330 MGMT_OP_SET_STATIC_ADDRESS,
3331 MGMT_STATUS_INVALID_PARAMS);
3332
3333 /* Two most significant bits shall be set */
3334 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3335 return cmd_status(sk, hdev->id,
3336 MGMT_OP_SET_STATIC_ADDRESS,
3337 MGMT_STATUS_INVALID_PARAMS);
3338 }
3339
3340 hci_dev_lock(hdev);
3341
3342 bacpy(&hdev->static_addr, &cp->bdaddr);
3343
3344 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3345
3346 hci_dev_unlock(hdev);
3347
3348 return err;
3349}
3350
Johan Hedberg33e38b32013-03-15 17:07:05 -05003351static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3352{
3353 struct pending_cmd *cmd;
3354
3355 BT_DBG("status 0x%02x", status);
3356
3357 hci_dev_lock(hdev);
3358
3359 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3360 if (!cmd)
3361 goto unlock;
3362
3363 if (status) {
3364 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3365 mgmt_status(status));
3366 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003367 struct mgmt_mode *cp = cmd->param;
3368
3369 if (cp->val)
3370 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3371 else
3372 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3373
Johan Hedberg33e38b32013-03-15 17:07:05 -05003374 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3375 new_settings(hdev, cmd->sk);
3376 }
3377
3378 mgmt_pending_remove(cmd);
3379
3380unlock:
3381 hci_dev_unlock(hdev);
3382}
3383
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003384static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003385 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003386{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003387 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003388 struct pending_cmd *cmd;
3389 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003390 int err;
3391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003392 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003393
Johan Hedberg56f87902013-10-02 13:43:13 +03003394 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3395 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003396 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3397 MGMT_STATUS_NOT_SUPPORTED);
3398
Johan Hedberga7e80f22013-01-09 16:05:19 +02003399 if (cp->val != 0x00 && cp->val != 0x01)
3400 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3401 MGMT_STATUS_INVALID_PARAMS);
3402
Johan Hedberg5400c042012-02-21 16:40:33 +02003403 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003404 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003406
3407 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003408 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003409 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003410
3411 hci_dev_lock(hdev);
3412
Johan Hedberg05cbf292013-03-15 17:07:07 -05003413 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3414 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3415 MGMT_STATUS_BUSY);
3416 goto unlock;
3417 }
3418
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003419 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3420 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3421 hdev);
3422 goto unlock;
3423 }
3424
Johan Hedberg33e38b32013-03-15 17:07:05 -05003425 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3426 data, len);
3427 if (!cmd) {
3428 err = -ENOMEM;
3429 goto unlock;
3430 }
3431
3432 hci_req_init(&req, hdev);
3433
Johan Hedberg406d7802013-03-15 17:07:09 -05003434 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003435
3436 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003437 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003438 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003439 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003440 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003441 }
3442
Johan Hedberg33e38b32013-03-15 17:07:05 -05003443unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003444 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003445
Antti Julkuf6422ec2011-06-22 13:11:56 +03003446 return err;
3447}
3448
Johan Hedberg0663ca22013-10-02 13:43:14 +03003449static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3450{
3451 struct pending_cmd *cmd;
3452
3453 BT_DBG("status 0x%02x", status);
3454
3455 hci_dev_lock(hdev);
3456
3457 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3458 if (!cmd)
3459 goto unlock;
3460
3461 if (status) {
3462 u8 mgmt_err = mgmt_status(status);
3463
3464 /* We need to restore the flag if related HCI commands
3465 * failed.
3466 */
3467 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3468
3469 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3470 } else {
3471 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3472 new_settings(hdev, cmd->sk);
3473 }
3474
3475 mgmt_pending_remove(cmd);
3476
3477unlock:
3478 hci_dev_unlock(hdev);
3479}
3480
3481static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3482{
3483 struct mgmt_mode *cp = data;
3484 struct pending_cmd *cmd;
3485 struct hci_request req;
3486 int err;
3487
3488 BT_DBG("request for %s", hdev->name);
3489
3490 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3491 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3492 MGMT_STATUS_NOT_SUPPORTED);
3493
3494 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3495 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3496 MGMT_STATUS_REJECTED);
3497
3498 if (cp->val != 0x00 && cp->val != 0x01)
3499 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3500 MGMT_STATUS_INVALID_PARAMS);
3501
3502 hci_dev_lock(hdev);
3503
3504 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3505 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3506 goto unlock;
3507 }
3508
3509 if (!hdev_is_powered(hdev)) {
3510 if (!cp->val) {
3511 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3512 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3513 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3514 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3515 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3516 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3517 }
3518
3519 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3520
3521 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3522 if (err < 0)
3523 goto unlock;
3524
3525 err = new_settings(hdev, sk);
3526 goto unlock;
3527 }
3528
3529 /* Reject disabling when powered on */
3530 if (!cp->val) {
3531 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3532 MGMT_STATUS_REJECTED);
3533 goto unlock;
3534 }
3535
3536 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3537 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3538 MGMT_STATUS_BUSY);
3539 goto unlock;
3540 }
3541
3542 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3543 if (!cmd) {
3544 err = -ENOMEM;
3545 goto unlock;
3546 }
3547
3548 /* We need to flip the bit already here so that hci_update_ad
3549 * generates the correct flags.
3550 */
3551 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3552
3553 hci_req_init(&req, hdev);
3554 hci_update_ad(&req);
3555 err = hci_req_run(&req, set_bredr_complete);
3556 if (err < 0)
3557 mgmt_pending_remove(cmd);
3558
3559unlock:
3560 hci_dev_unlock(hdev);
3561 return err;
3562}
3563
Johan Hedberg3f706b72013-01-20 14:27:16 +02003564static bool ltk_is_valid(struct mgmt_ltk_info *key)
3565{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003566 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3567 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003568 if (key->master != 0x00 && key->master != 0x01)
3569 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003570 if (!bdaddr_type_is_le(key->addr.type))
3571 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003572 return true;
3573}
3574
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003575static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003576 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003577{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003578 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3579 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003580 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003581
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003582 BT_DBG("request for %s", hdev->name);
3583
3584 if (!lmp_le_capable(hdev))
3585 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3586 MGMT_STATUS_NOT_SUPPORTED);
3587
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003588 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003589
3590 expected_len = sizeof(*cp) + key_count *
3591 sizeof(struct mgmt_ltk_info);
3592 if (expected_len != len) {
3593 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003594 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003595 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003596 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003597 }
3598
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003599 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003600
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003601 for (i = 0; i < key_count; i++) {
3602 struct mgmt_ltk_info *key = &cp->keys[i];
3603
Johan Hedberg3f706b72013-01-20 14:27:16 +02003604 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003605 return cmd_status(sk, hdev->id,
3606 MGMT_OP_LOAD_LONG_TERM_KEYS,
3607 MGMT_STATUS_INVALID_PARAMS);
3608 }
3609
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003610 hci_dev_lock(hdev);
3611
3612 hci_smp_ltks_clear(hdev);
3613
3614 for (i = 0; i < key_count; i++) {
3615 struct mgmt_ltk_info *key = &cp->keys[i];
3616 u8 type;
3617
3618 if (key->master)
3619 type = HCI_SMP_LTK;
3620 else
3621 type = HCI_SMP_LTK_SLAVE;
3622
Hemant Gupta4596fde2012-04-16 14:57:40 +05303623 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003624 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003625 type, 0, key->authenticated, key->val,
3626 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003627 }
3628
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003629 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3630 NULL, 0);
3631
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003632 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003633
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003634 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003635}
3636
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003637static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003638 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3639 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003640 bool var_len;
3641 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003642} mgmt_handlers[] = {
3643 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003644 { read_version, false, MGMT_READ_VERSION_SIZE },
3645 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3646 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3647 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3648 { set_powered, false, MGMT_SETTING_SIZE },
3649 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3650 { set_connectable, false, MGMT_SETTING_SIZE },
3651 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3652 { set_pairable, false, MGMT_SETTING_SIZE },
3653 { set_link_security, false, MGMT_SETTING_SIZE },
3654 { set_ssp, false, MGMT_SETTING_SIZE },
3655 { set_hs, false, MGMT_SETTING_SIZE },
3656 { set_le, false, MGMT_SETTING_SIZE },
3657 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3658 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3659 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3660 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3661 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3662 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3663 { disconnect, false, MGMT_DISCONNECT_SIZE },
3664 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3665 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3666 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3667 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3668 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3669 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3670 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3671 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3672 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3673 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3674 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3675 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3676 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3677 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3678 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3679 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3680 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3681 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3682 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003683 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003684 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003685 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003686 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003687};
3688
3689
Johan Hedberg03811012010-12-08 00:21:06 +02003690int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3691{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003692 void *buf;
3693 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003694 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003695 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003696 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003697 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003698 int err;
3699
3700 BT_DBG("got %zu bytes", msglen);
3701
3702 if (msglen < sizeof(*hdr))
3703 return -EINVAL;
3704
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003705 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003706 if (!buf)
3707 return -ENOMEM;
3708
3709 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3710 err = -EFAULT;
3711 goto done;
3712 }
3713
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003714 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003715 opcode = __le16_to_cpu(hdr->opcode);
3716 index = __le16_to_cpu(hdr->index);
3717 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003718
3719 if (len != msglen - sizeof(*hdr)) {
3720 err = -EINVAL;
3721 goto done;
3722 }
3723
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003724 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003725 hdev = hci_dev_get(index);
3726 if (!hdev) {
3727 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003728 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003729 goto done;
3730 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003731
3732 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3733 err = cmd_status(sk, index, opcode,
3734 MGMT_STATUS_INVALID_INDEX);
3735 goto done;
3736 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003737 }
3738
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003739 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003740 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003741 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003742 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003743 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003744 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003745 }
3746
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003747 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003748 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003749 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003750 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003751 goto done;
3752 }
3753
Johan Hedbergbe22b542012-03-01 22:24:41 +02003754 handler = &mgmt_handlers[opcode];
3755
3756 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003757 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003758 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003759 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003760 goto done;
3761 }
3762
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003763 if (hdev)
3764 mgmt_init_hdev(sk, hdev);
3765
3766 cp = buf + sizeof(*hdr);
3767
Johan Hedbergbe22b542012-03-01 22:24:41 +02003768 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003769 if (err < 0)
3770 goto done;
3771
Johan Hedberg03811012010-12-08 00:21:06 +02003772 err = msglen;
3773
3774done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003775 if (hdev)
3776 hci_dev_put(hdev);
3777
Johan Hedberg03811012010-12-08 00:21:06 +02003778 kfree(buf);
3779 return err;
3780}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003781
Johan Hedberg744cf192011-11-08 20:40:14 +02003782int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003783{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003784 if (!mgmt_valid_hdev(hdev))
3785 return -ENOTSUPP;
3786
Johan Hedberg744cf192011-11-08 20:40:14 +02003787 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003788}
3789
Johan Hedberg744cf192011-11-08 20:40:14 +02003790int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003791{
Johan Hedberg5f159032012-03-02 03:13:19 +02003792 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003793
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003794 if (!mgmt_valid_hdev(hdev))
3795 return -ENOTSUPP;
3796
Johan Hedberg744cf192011-11-08 20:40:14 +02003797 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003798
Johan Hedberg744cf192011-11-08 20:40:14 +02003799 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003800}
3801
Johan Hedberg890ea892013-03-15 17:06:52 -05003802static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003803{
Johan Hedberg890ea892013-03-15 17:06:52 -05003804 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003805 u8 scan = 0;
3806
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003807 /* Ensure that fast connectable is disabled. This function will
3808 * not do anything if the page scan parameters are already what
3809 * they should be.
3810 */
3811 write_fast_connectable(req, false);
3812
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003813 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3814 scan |= SCAN_PAGE;
3815 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3816 scan |= SCAN_INQUIRY;
3817
Johan Hedberg890ea892013-03-15 17:06:52 -05003818 if (scan)
3819 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003820}
3821
Johan Hedberg229ab392013-03-15 17:06:53 -05003822static void powered_complete(struct hci_dev *hdev, u8 status)
3823{
3824 struct cmd_lookup match = { NULL, hdev };
3825
3826 BT_DBG("status 0x%02x", status);
3827
3828 hci_dev_lock(hdev);
3829
3830 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3831
3832 new_settings(hdev, match.sk);
3833
3834 hci_dev_unlock(hdev);
3835
3836 if (match.sk)
3837 sock_put(match.sk);
3838}
3839
Johan Hedberg70da6242013-03-15 17:06:51 -05003840static int powered_update_hci(struct hci_dev *hdev)
3841{
Johan Hedberg890ea892013-03-15 17:06:52 -05003842 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003843 u8 link_sec;
3844
Johan Hedberg890ea892013-03-15 17:06:52 -05003845 hci_req_init(&req, hdev);
3846
Johan Hedberg70da6242013-03-15 17:06:51 -05003847 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3848 !lmp_host_ssp_capable(hdev)) {
3849 u8 ssp = 1;
3850
Johan Hedberg890ea892013-03-15 17:06:52 -05003851 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003852 }
3853
Johan Hedbergc73eee92013-04-19 18:35:21 +03003854 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3855 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003856 struct hci_cp_write_le_host_supported cp;
3857
3858 cp.le = 1;
3859 cp.simul = lmp_le_br_capable(hdev);
3860
3861 /* Check first if we already have the right
3862 * host state (host features set)
3863 */
3864 if (cp.le != lmp_host_le_capable(hdev) ||
3865 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003866 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3867 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003868
3869 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3870 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003871 }
3872
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003873 if (lmp_le_capable(hdev)) {
3874 /* Set random address to static address if configured */
3875 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3876 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3877 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003878
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003879 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3880 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003881 }
3882
Johan Hedberg70da6242013-03-15 17:06:51 -05003883 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3884 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003885 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3886 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003887
3888 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003889 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3890 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003891 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003892 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003893 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003894 }
3895
Johan Hedberg229ab392013-03-15 17:06:53 -05003896 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003897}
3898
Johan Hedberg744cf192011-11-08 20:40:14 +02003899int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003900{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003901 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003902 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3903 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003904 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003905
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003906 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3907 return 0;
3908
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003909 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003910 if (powered_update_hci(hdev) == 0)
3911 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003912
Johan Hedberg229ab392013-03-15 17:06:53 -05003913 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3914 &match);
3915 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003916 }
3917
Johan Hedberg229ab392013-03-15 17:06:53 -05003918 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3919 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3920
3921 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3922 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3923 zero_cod, sizeof(zero_cod), NULL);
3924
3925new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003926 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003927
3928 if (match.sk)
3929 sock_put(match.sk);
3930
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003931 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003932}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003933
Johan Hedberg96570ff2013-05-29 09:51:29 +03003934int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3935{
3936 struct pending_cmd *cmd;
3937 u8 status;
3938
3939 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3940 if (!cmd)
3941 return -ENOENT;
3942
3943 if (err == -ERFKILL)
3944 status = MGMT_STATUS_RFKILLED;
3945 else
3946 status = MGMT_STATUS_FAILED;
3947
3948 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3949
3950 mgmt_pending_remove(cmd);
3951
3952 return err;
3953}
3954
Johan Hedberg744cf192011-11-08 20:40:14 +02003955int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003956{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003957 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003958 bool changed = false;
3959 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003960
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003961 if (discoverable) {
3962 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3963 changed = true;
3964 } else {
3965 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3966 changed = true;
3967 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003968
Johan Hedberged9b5f22012-02-21 20:47:06 +02003969 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003970 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003971
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003972 if (changed)
3973 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003974
Johan Hedberg73f22f62010-12-29 16:00:25 +02003975 if (match.sk)
3976 sock_put(match.sk);
3977
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003978 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003979}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003980
Johan Hedberg744cf192011-11-08 20:40:14 +02003981int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003982{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003983 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003984 bool changed = false;
3985 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003986
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003987 if (connectable) {
3988 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3989 changed = true;
3990 } else {
3991 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3992 changed = true;
3993 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003994
Johan Hedberg2b76f452013-03-15 17:07:04 -05003995 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003996
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003997 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003998 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003999
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004000 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004001}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004002
Johan Hedberg744cf192011-11-08 20:40:14 +02004003int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004004{
Johan Hedbergca69b792011-11-11 18:10:00 +02004005 u8 mgmt_err = mgmt_status(status);
4006
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004007 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004008 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004009 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004010
4011 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004012 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004013 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004014
4015 return 0;
4016}
4017
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004018int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4019 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004020{
Johan Hedberg86742e12011-11-07 23:13:38 +02004021 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004022
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004023 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004024
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004025 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004026 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004027 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004028 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004029 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004030 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004031
Johan Hedberg744cf192011-11-08 20:40:14 +02004032 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004033}
Johan Hedbergf7520542011-01-20 12:34:39 +02004034
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004035int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4036{
4037 struct mgmt_ev_new_long_term_key ev;
4038
4039 memset(&ev, 0, sizeof(ev));
4040
4041 ev.store_hint = persistent;
4042 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004043 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004044 ev.key.authenticated = key->authenticated;
4045 ev.key.enc_size = key->enc_size;
4046 ev.key.ediv = key->ediv;
4047
4048 if (key->type == HCI_SMP_LTK)
4049 ev.key.master = 1;
4050
4051 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4052 memcpy(ev.key.val, key->val, sizeof(key->val));
4053
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004054 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4055 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004056}
4057
Johan Hedbergafc747a2012-01-15 18:11:07 +02004058int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004059 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4060 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004061{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004062 char buf[512];
4063 struct mgmt_ev_device_connected *ev = (void *) buf;
4064 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004065
Johan Hedbergb644ba32012-01-17 21:48:47 +02004066 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004067 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004068
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004069 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004070
Johan Hedbergb644ba32012-01-17 21:48:47 +02004071 if (name_len > 0)
4072 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004073 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004074
4075 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004076 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004077 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004078
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004079 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004080
4081 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004082 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004083}
4084
Johan Hedberg8962ee72011-01-20 12:40:27 +02004085static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4086{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004087 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004088 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004089 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004090
Johan Hedberg88c3df12012-02-09 14:27:38 +02004091 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4092 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004093
Johan Hedbergaee9b212012-02-18 15:07:59 +02004094 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004095 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004096
4097 *sk = cmd->sk;
4098 sock_hold(*sk);
4099
Johan Hedberga664b5b2011-02-19 12:06:02 -03004100 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004101}
4102
Johan Hedberg124f6e32012-02-09 13:50:12 +02004103static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004104{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004105 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004106 struct mgmt_cp_unpair_device *cp = cmd->param;
4107 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004108
4109 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004110 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4111 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004112
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004113 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4114
Johan Hedbergaee9b212012-02-18 15:07:59 +02004115 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004116
4117 mgmt_pending_remove(cmd);
4118}
4119
Johan Hedbergafc747a2012-01-15 18:11:07 +02004120int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004121 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004122{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004123 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004124 struct sock *sk = NULL;
4125 int err;
4126
Johan Hedberg744cf192011-11-08 20:40:14 +02004127 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004128
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004129 bacpy(&ev.addr.bdaddr, bdaddr);
4130 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4131 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004132
Johan Hedbergafc747a2012-01-15 18:11:07 +02004133 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004134 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004135
4136 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004137 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004138
Johan Hedberg124f6e32012-02-09 13:50:12 +02004139 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004140 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004141
Johan Hedberg8962ee72011-01-20 12:40:27 +02004142 return err;
4143}
4144
Johan Hedberg88c3df12012-02-09 14:27:38 +02004145int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004146 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004147{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004148 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004149 struct pending_cmd *cmd;
4150 int err;
4151
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004152 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4153 hdev);
4154
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004155 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004156 if (!cmd)
4157 return -ENOENT;
4158
Johan Hedberg88c3df12012-02-09 14:27:38 +02004159 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004160 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004161
Johan Hedberg88c3df12012-02-09 14:27:38 +02004162 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004163 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004164
Johan Hedberga664b5b2011-02-19 12:06:02 -03004165 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004166
4167 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004168}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004169
Johan Hedberg48264f02011-11-09 13:58:58 +02004170int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004171 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004172{
4173 struct mgmt_ev_connect_failed ev;
4174
Johan Hedberg4c659c32011-11-07 23:13:39 +02004175 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004176 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004177 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004178
Johan Hedberg744cf192011-11-08 20:40:14 +02004179 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004180}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004181
Johan Hedberg744cf192011-11-08 20:40:14 +02004182int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004183{
4184 struct mgmt_ev_pin_code_request ev;
4185
Johan Hedbergd8457692012-02-17 14:24:57 +02004186 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004187 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004188 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004189
Johan Hedberg744cf192011-11-08 20:40:14 +02004190 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004191 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004192}
4193
Johan Hedberg744cf192011-11-08 20:40:14 +02004194int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004195 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004196{
4197 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004198 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004199 int err;
4200
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004201 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004202 if (!cmd)
4203 return -ENOENT;
4204
Johan Hedbergd8457692012-02-17 14:24:57 +02004205 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004206 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004207
Johan Hedbergaee9b212012-02-18 15:07:59 +02004208 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004209 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004210
Johan Hedberga664b5b2011-02-19 12:06:02 -03004211 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004212
4213 return err;
4214}
4215
Johan Hedberg744cf192011-11-08 20:40:14 +02004216int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004217 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004218{
4219 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004220 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004221 int err;
4222
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004223 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004224 if (!cmd)
4225 return -ENOENT;
4226
Johan Hedbergd8457692012-02-17 14:24:57 +02004227 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004228 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004229
Johan Hedbergaee9b212012-02-18 15:07:59 +02004230 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004231 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004232
Johan Hedberga664b5b2011-02-19 12:06:02 -03004233 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004234
4235 return err;
4236}
Johan Hedberga5c29682011-02-19 12:05:57 -03004237
Johan Hedberg744cf192011-11-08 20:40:14 +02004238int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004239 u8 link_type, u8 addr_type, __le32 value,
4240 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004241{
4242 struct mgmt_ev_user_confirm_request ev;
4243
Johan Hedberg744cf192011-11-08 20:40:14 +02004244 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004245
Johan Hedberg272d90d2012-02-09 15:26:12 +02004246 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004247 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004248 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004249 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004250
Johan Hedberg744cf192011-11-08 20:40:14 +02004251 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004252 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004253}
4254
Johan Hedberg272d90d2012-02-09 15:26:12 +02004255int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004256 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004257{
4258 struct mgmt_ev_user_passkey_request ev;
4259
4260 BT_DBG("%s", hdev->name);
4261
Johan Hedberg272d90d2012-02-09 15:26:12 +02004262 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004263 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004264
4265 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004266 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004267}
4268
Brian Gix0df4c182011-11-16 13:53:13 -08004269static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004270 u8 link_type, u8 addr_type, u8 status,
4271 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004272{
4273 struct pending_cmd *cmd;
4274 struct mgmt_rp_user_confirm_reply rp;
4275 int err;
4276
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004277 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004278 if (!cmd)
4279 return -ENOENT;
4280
Johan Hedberg272d90d2012-02-09 15:26:12 +02004281 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004282 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004283 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004284 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004285
Johan Hedberga664b5b2011-02-19 12:06:02 -03004286 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004287
4288 return err;
4289}
4290
Johan Hedberg744cf192011-11-08 20:40:14 +02004291int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004292 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004293{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004294 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004295 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004296}
4297
Johan Hedberg272d90d2012-02-09 15:26:12 +02004298int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004299 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004300{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004301 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004302 status,
4303 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004304}
Johan Hedberg2a611692011-02-19 12:06:00 -03004305
Brian Gix604086b2011-11-23 08:28:33 -08004306int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004307 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004308{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004309 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004310 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004311}
4312
Johan Hedberg272d90d2012-02-09 15:26:12 +02004313int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004314 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004315{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004316 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004317 status,
4318 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004319}
4320
Johan Hedberg92a25252012-09-06 18:39:26 +03004321int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4322 u8 link_type, u8 addr_type, u32 passkey,
4323 u8 entered)
4324{
4325 struct mgmt_ev_passkey_notify ev;
4326
4327 BT_DBG("%s", hdev->name);
4328
4329 bacpy(&ev.addr.bdaddr, bdaddr);
4330 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4331 ev.passkey = __cpu_to_le32(passkey);
4332 ev.entered = entered;
4333
4334 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4335}
4336
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004337int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004338 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004339{
4340 struct mgmt_ev_auth_failed ev;
4341
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004342 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004343 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004344 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004345
Johan Hedberg744cf192011-11-08 20:40:14 +02004346 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004347}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004348
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004349int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4350{
4351 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004352 bool changed = false;
4353 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004354
4355 if (status) {
4356 u8 mgmt_err = mgmt_status(status);
4357 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004358 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004359 return 0;
4360 }
4361
Johan Hedberg47990ea2012-02-22 11:58:37 +02004362 if (test_bit(HCI_AUTH, &hdev->flags)) {
4363 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4364 changed = true;
4365 } else {
4366 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4367 changed = true;
4368 }
4369
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004370 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004371 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004372
Johan Hedberg47990ea2012-02-22 11:58:37 +02004373 if (changed)
4374 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004375
4376 if (match.sk)
4377 sock_put(match.sk);
4378
4379 return err;
4380}
4381
Johan Hedberg890ea892013-03-15 17:06:52 -05004382static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004383{
Johan Hedberg890ea892013-03-15 17:06:52 -05004384 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004385 struct hci_cp_write_eir cp;
4386
Johan Hedberg976eb202012-10-24 21:12:01 +03004387 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004388 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004389
Johan Hedbergc80da272012-02-22 15:38:48 +02004390 memset(hdev->eir, 0, sizeof(hdev->eir));
4391
Johan Hedbergcacaf522012-02-21 00:52:42 +02004392 memset(&cp, 0, sizeof(cp));
4393
Johan Hedberg890ea892013-03-15 17:06:52 -05004394 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004395}
4396
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004397int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004398{
4399 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004400 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004401 bool changed = false;
4402 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004403
4404 if (status) {
4405 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004406
4407 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004408 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004409 err = new_settings(hdev, NULL);
4410
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004411 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4412 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004413
4414 return err;
4415 }
4416
4417 if (enable) {
4418 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4419 changed = true;
4420 } else {
4421 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4422 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004423 }
4424
4425 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4426
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004427 if (changed)
4428 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004429
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004430 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004431 sock_put(match.sk);
4432
Johan Hedberg890ea892013-03-15 17:06:52 -05004433 hci_req_init(&req, hdev);
4434
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004435 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004436 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004437 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004438 clear_eir(&req);
4439
4440 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004441
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004442 return err;
4443}
4444
Johan Hedberg92da6092013-03-15 17:06:55 -05004445static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004446{
4447 struct cmd_lookup *match = data;
4448
Johan Hedberg90e70452012-02-23 23:09:40 +02004449 if (match->sk == NULL) {
4450 match->sk = cmd->sk;
4451 sock_hold(match->sk);
4452 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004453}
4454
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004455int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004456 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004457{
Johan Hedberg90e70452012-02-23 23:09:40 +02004458 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4459 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004460
Johan Hedberg92da6092013-03-15 17:06:55 -05004461 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4462 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4463 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004464
4465 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004466 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4467 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004468
4469 if (match.sk)
4470 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004471
4472 return err;
4473}
4474
Johan Hedberg744cf192011-11-08 20:40:14 +02004475int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004476{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004477 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004478 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004479
Johan Hedberg13928972013-03-15 17:07:00 -05004480 if (status)
4481 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004482
4483 memset(&ev, 0, sizeof(ev));
4484 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004485 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004486
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004487 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004488 if (!cmd) {
4489 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004490
Johan Hedberg13928972013-03-15 17:07:00 -05004491 /* If this is a HCI command related to powering on the
4492 * HCI dev don't send any mgmt signals.
4493 */
4494 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4495 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004496 }
4497
Johan Hedberg13928972013-03-15 17:07:00 -05004498 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4499 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004500}
Szymon Jancc35938b2011-03-22 13:12:21 +01004501
Johan Hedberg744cf192011-11-08 20:40:14 +02004502int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004503 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004504{
4505 struct pending_cmd *cmd;
4506 int err;
4507
Johan Hedberg744cf192011-11-08 20:40:14 +02004508 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004509
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004510 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004511 if (!cmd)
4512 return -ENOENT;
4513
4514 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004515 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4516 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004517 } else {
4518 struct mgmt_rp_read_local_oob_data rp;
4519
4520 memcpy(rp.hash, hash, sizeof(rp.hash));
4521 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4522
Johan Hedberg744cf192011-11-08 20:40:14 +02004523 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004524 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4525 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004526 }
4527
4528 mgmt_pending_remove(cmd);
4529
4530 return err;
4531}
Johan Hedberge17acd42011-03-30 23:57:16 +03004532
Johan Hedberg48264f02011-11-09 13:58:58 +02004533int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004534 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4535 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004536{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004537 char buf[512];
4538 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004539 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004540
Andre Guedes12602d02013-04-30 15:29:40 -03004541 if (!hci_discovery_active(hdev))
4542 return -EPERM;
4543
Johan Hedberg1dc06092012-01-15 21:01:23 +02004544 /* Leave 5 bytes for a potential CoD field */
4545 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004546 return -EINVAL;
4547
Johan Hedberg1dc06092012-01-15 21:01:23 +02004548 memset(buf, 0, sizeof(buf));
4549
Johan Hedberge319d2e2012-01-15 19:51:59 +02004550 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004551 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004552 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004553 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304554 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004555 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304556 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004557
Johan Hedberg1dc06092012-01-15 21:01:23 +02004558 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004559 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004560
Johan Hedberg1dc06092012-01-15 21:01:23 +02004561 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4562 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004563 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004564
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004565 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004566 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004567
Johan Hedberge319d2e2012-01-15 19:51:59 +02004568 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004569}
Johan Hedberga88a9652011-03-30 13:18:12 +03004570
Johan Hedbergb644ba32012-01-17 21:48:47 +02004571int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004572 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004573{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004574 struct mgmt_ev_device_found *ev;
4575 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4576 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004577
Johan Hedbergb644ba32012-01-17 21:48:47 +02004578 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004579
Johan Hedbergb644ba32012-01-17 21:48:47 +02004580 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004581
Johan Hedbergb644ba32012-01-17 21:48:47 +02004582 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004583 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004584 ev->rssi = rssi;
4585
4586 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004587 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004588
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004589 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004590
Johan Hedberg053c7e02012-02-04 00:06:00 +02004591 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004592 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004593}
Johan Hedberg314b2382011-04-27 10:29:57 -04004594
Johan Hedberg744cf192011-11-08 20:40:14 +02004595int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004596{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004597 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004598 struct pending_cmd *cmd;
4599
Andre Guedes343fb142011-11-22 17:14:19 -03004600 BT_DBG("%s discovering %u", hdev->name, discovering);
4601
Johan Hedberg164a6e72011-11-01 17:06:44 +02004602 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004603 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004604 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004605 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004606
4607 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004608 u8 type = hdev->discovery.type;
4609
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4611 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004612 mgmt_pending_remove(cmd);
4613 }
4614
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004615 memset(&ev, 0, sizeof(ev));
4616 ev.type = hdev->discovery.type;
4617 ev.discovering = discovering;
4618
4619 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004620}
Antti Julku5e762442011-08-25 16:48:02 +03004621
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004622int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004623{
4624 struct pending_cmd *cmd;
4625 struct mgmt_ev_device_blocked ev;
4626
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004627 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004628
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004629 bacpy(&ev.addr.bdaddr, bdaddr);
4630 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004631
Johan Hedberg744cf192011-11-08 20:40:14 +02004632 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004633 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004634}
4635
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004636int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004637{
4638 struct pending_cmd *cmd;
4639 struct mgmt_ev_device_unblocked ev;
4640
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004641 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004642
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004643 bacpy(&ev.addr.bdaddr, bdaddr);
4644 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004645
Johan Hedberg744cf192011-11-08 20:40:14 +02004646 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004647 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004648}