blob: 6e808d1d78f39f0abd6175692ba2562cf73530af [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 Hedberg84bde9d2012-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 Hedberg84bde9d2012-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
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001414static void le_enable_complete(struct hci_dev *hdev, u8 status)
1415{
1416 struct cmd_lookup match = { NULL, hdev };
1417
1418 if (status) {
1419 u8 mgmt_err = mgmt_status(status);
1420
1421 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1422 &mgmt_err);
1423 return;
1424 }
1425
1426 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1427
1428 new_settings(hdev, match.sk);
1429
1430 if (match.sk)
1431 sock_put(match.sk);
1432}
1433
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001434static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001435{
1436 struct mgmt_mode *cp = data;
1437 struct hci_cp_write_le_host_supported hci_cp;
1438 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001439 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001440 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001441 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001442
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001443 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001444
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001445 if (!lmp_le_capable(hdev))
1446 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1447 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001448
Johan Hedberga7e80f22013-01-09 16:05:19 +02001449 if (cp->val != 0x00 && cp->val != 0x01)
1450 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1451 MGMT_STATUS_INVALID_PARAMS);
1452
Johan Hedbergc73eee92013-04-19 18:35:21 +03001453 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001454 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001455 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1456 MGMT_STATUS_REJECTED);
1457
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001458 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001459
1460 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001461 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001462
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001463 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001464 bool changed = false;
1465
1466 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1467 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1468 changed = true;
1469 }
1470
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001471 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1472 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001473 changed = true;
1474 }
1475
Johan Hedberg06199cf2012-02-22 16:37:11 +02001476 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1477 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001478 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001479
1480 if (changed)
1481 err = new_settings(hdev, sk);
1482
Johan Hedberg1de028c2012-02-29 19:55:35 -08001483 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001484 }
1485
Johan Hedberg4375f102013-09-25 13:26:10 +03001486 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1487 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001488 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001489 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001490 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001491 }
1492
1493 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1494 if (!cmd) {
1495 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001496 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001497 }
1498
1499 memset(&hci_cp, 0, sizeof(hci_cp));
1500
1501 if (val) {
1502 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001503 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001504 }
1505
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001506 hci_req_init(&req, hdev);
1507
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001508 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001509 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1510
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001511 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1512 &hci_cp);
1513
1514 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301515 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001516 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001517
Johan Hedberg1de028c2012-02-29 19:55:35 -08001518unlock:
1519 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001520 return err;
1521}
1522
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001523/* This is a helper function to test for pending mgmt commands that can
1524 * cause CoD or EIR HCI commands. We can only allow one such pending
1525 * mgmt command at a time since otherwise we cannot easily track what
1526 * the current values are, will be, and based on that calculate if a new
1527 * HCI command needs to be sent and if yes with what value.
1528 */
1529static bool pending_eir_or_class(struct hci_dev *hdev)
1530{
1531 struct pending_cmd *cmd;
1532
1533 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1534 switch (cmd->opcode) {
1535 case MGMT_OP_ADD_UUID:
1536 case MGMT_OP_REMOVE_UUID:
1537 case MGMT_OP_SET_DEV_CLASS:
1538 case MGMT_OP_SET_POWERED:
1539 return true;
1540 }
1541 }
1542
1543 return false;
1544}
1545
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001546static const u8 bluetooth_base_uuid[] = {
1547 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1548 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1549};
1550
1551static u8 get_uuid_size(const u8 *uuid)
1552{
1553 u32 val;
1554
1555 if (memcmp(uuid, bluetooth_base_uuid, 12))
1556 return 128;
1557
1558 val = get_unaligned_le32(&uuid[12]);
1559 if (val > 0xffff)
1560 return 32;
1561
1562 return 16;
1563}
1564
Johan Hedberg92da6092013-03-15 17:06:55 -05001565static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1566{
1567 struct pending_cmd *cmd;
1568
1569 hci_dev_lock(hdev);
1570
1571 cmd = mgmt_pending_find(mgmt_op, hdev);
1572 if (!cmd)
1573 goto unlock;
1574
1575 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1576 hdev->dev_class, 3);
1577
1578 mgmt_pending_remove(cmd);
1579
1580unlock:
1581 hci_dev_unlock(hdev);
1582}
1583
1584static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1585{
1586 BT_DBG("status 0x%02x", status);
1587
1588 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1589}
1590
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001591static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001592{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001593 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001594 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001595 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001596 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001597 int err;
1598
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001599 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001600
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001601 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001602
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001603 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001604 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001605 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001606 goto failed;
1607 }
1608
Andre Guedes92c4c202012-06-07 19:05:44 -03001609 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001610 if (!uuid) {
1611 err = -ENOMEM;
1612 goto failed;
1613 }
1614
1615 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001616 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001617 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001618
Johan Hedbergde66aa62013-01-27 00:31:27 +02001619 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001620
Johan Hedberg890ea892013-03-15 17:06:52 -05001621 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001622
Johan Hedberg890ea892013-03-15 17:06:52 -05001623 update_class(&req);
1624 update_eir(&req);
1625
Johan Hedberg92da6092013-03-15 17:06:55 -05001626 err = hci_req_run(&req, add_uuid_complete);
1627 if (err < 0) {
1628 if (err != -ENODATA)
1629 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001630
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001631 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001632 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001633 goto failed;
1634 }
1635
1636 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001637 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001638 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001639 goto failed;
1640 }
1641
1642 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001643
1644failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001645 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001646 return err;
1647}
1648
Johan Hedberg24b78d02012-02-23 23:24:30 +02001649static bool enable_service_cache(struct hci_dev *hdev)
1650{
1651 if (!hdev_is_powered(hdev))
1652 return false;
1653
1654 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001655 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1656 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001657 return true;
1658 }
1659
1660 return false;
1661}
1662
Johan Hedberg92da6092013-03-15 17:06:55 -05001663static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1664{
1665 BT_DBG("status 0x%02x", status);
1666
1667 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1668}
1669
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001670static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001671 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001672{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001673 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001674 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001675 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001676 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 -05001677 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001678 int err, found;
1679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001680 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001681
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001682 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001683
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001684 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001685 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001686 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001687 goto unlock;
1688 }
1689
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001690 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1691 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001692
Johan Hedberg24b78d02012-02-23 23:24:30 +02001693 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001694 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001695 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001696 goto unlock;
1697 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001698
Johan Hedberg9246a862012-02-23 21:33:16 +02001699 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001700 }
1701
1702 found = 0;
1703
Johan Hedberg056341c2013-01-27 00:31:30 +02001704 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001705 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1706 continue;
1707
1708 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001709 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001710 found++;
1711 }
1712
1713 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001714 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001715 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001716 goto unlock;
1717 }
1718
Johan Hedberg9246a862012-02-23 21:33:16 +02001719update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001720 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001721
Johan Hedberg890ea892013-03-15 17:06:52 -05001722 update_class(&req);
1723 update_eir(&req);
1724
Johan Hedberg92da6092013-03-15 17:06:55 -05001725 err = hci_req_run(&req, remove_uuid_complete);
1726 if (err < 0) {
1727 if (err != -ENODATA)
1728 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001730 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001731 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001732 goto unlock;
1733 }
1734
1735 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001736 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001737 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001738 goto unlock;
1739 }
1740
1741 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001742
1743unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001744 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001745 return err;
1746}
1747
Johan Hedberg92da6092013-03-15 17:06:55 -05001748static void set_class_complete(struct hci_dev *hdev, u8 status)
1749{
1750 BT_DBG("status 0x%02x", status);
1751
1752 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1753}
1754
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001755static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001756 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001757{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001758 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001759 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001760 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001761 int err;
1762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001763 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001764
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001765 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001766 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1767 MGMT_STATUS_NOT_SUPPORTED);
1768
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001769 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001770
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001771 if (pending_eir_or_class(hdev)) {
1772 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1773 MGMT_STATUS_BUSY);
1774 goto unlock;
1775 }
1776
1777 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1778 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1779 MGMT_STATUS_INVALID_PARAMS);
1780 goto unlock;
1781 }
1782
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001783 hdev->major_class = cp->major;
1784 hdev->minor_class = cp->minor;
1785
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001786 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001787 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001788 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001789 goto unlock;
1790 }
1791
Johan Hedberg890ea892013-03-15 17:06:52 -05001792 hci_req_init(&req, hdev);
1793
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001794 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001795 hci_dev_unlock(hdev);
1796 cancel_delayed_work_sync(&hdev->service_cache);
1797 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001798 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001799 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001800
Johan Hedberg890ea892013-03-15 17:06:52 -05001801 update_class(&req);
1802
Johan Hedberg92da6092013-03-15 17:06:55 -05001803 err = hci_req_run(&req, set_class_complete);
1804 if (err < 0) {
1805 if (err != -ENODATA)
1806 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001807
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001808 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001809 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001810 goto unlock;
1811 }
1812
1813 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001814 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001815 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001816 goto unlock;
1817 }
1818
1819 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001820
Johan Hedbergb5235a62012-02-21 14:32:24 +02001821unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001822 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001823 return err;
1824}
1825
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001826static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001827 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001828{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001829 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001830 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001831 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001832
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001833 BT_DBG("request for %s", hdev->name);
1834
1835 if (!lmp_bredr_capable(hdev))
1836 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1837 MGMT_STATUS_NOT_SUPPORTED);
1838
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001839 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001840
Johan Hedberg86742e12011-11-07 23:13:38 +02001841 expected_len = sizeof(*cp) + key_count *
1842 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001843 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001844 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001845 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001846 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001847 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001848 }
1849
Johan Hedberg4ae14302013-01-20 14:27:13 +02001850 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1851 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1852 MGMT_STATUS_INVALID_PARAMS);
1853
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001854 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001855 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001856
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001857 for (i = 0; i < key_count; i++) {
1858 struct mgmt_link_key_info *key = &cp->keys[i];
1859
1860 if (key->addr.type != BDADDR_BREDR)
1861 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1862 MGMT_STATUS_INVALID_PARAMS);
1863 }
1864
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001865 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001866
1867 hci_link_keys_clear(hdev);
1868
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001869 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001870 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001871 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001872 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001873
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001874 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001875 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001876
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001877 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001878 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879 }
1880
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001881 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001882
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001883 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001884
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001885 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001886}
1887
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001888static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001889 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001890{
1891 struct mgmt_ev_device_unpaired ev;
1892
1893 bacpy(&ev.addr.bdaddr, bdaddr);
1894 ev.addr.type = addr_type;
1895
1896 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001897 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001898}
1899
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001900static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001901 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001902{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001903 struct mgmt_cp_unpair_device *cp = data;
1904 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001905 struct hci_cp_disconnect dc;
1906 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001907 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001908 int err;
1909
Johan Hedberga8a1d192011-11-10 15:54:38 +02001910 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001911 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1912 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001913
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001914 if (!bdaddr_type_is_valid(cp->addr.type))
1915 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1916 MGMT_STATUS_INVALID_PARAMS,
1917 &rp, sizeof(rp));
1918
Johan Hedberg118da702013-01-20 14:27:20 +02001919 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1920 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1921 MGMT_STATUS_INVALID_PARAMS,
1922 &rp, sizeof(rp));
1923
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001924 hci_dev_lock(hdev);
1925
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001926 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001927 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001929 goto unlock;
1930 }
1931
Andre Guedes591f47f2012-04-24 21:02:49 -03001932 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001933 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1934 else
1935 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001936
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001937 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001938 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001939 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001940 goto unlock;
1941 }
1942
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001943 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001944 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001945 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001946 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001947 else
1948 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001949 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001950 } else {
1951 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001952 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001953
Johan Hedberga8a1d192011-11-10 15:54:38 +02001954 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001955 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001956 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001957 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001958 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001959 }
1960
Johan Hedberg124f6e32012-02-09 13:50:12 +02001961 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001962 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001963 if (!cmd) {
1964 err = -ENOMEM;
1965 goto unlock;
1966 }
1967
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001968 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001969 dc.reason = 0x13; /* Remote User Terminated Connection */
1970 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1971 if (err < 0)
1972 mgmt_pending_remove(cmd);
1973
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001974unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001975 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001976 return err;
1977}
1978
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001979static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001980 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001981{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001982 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001983 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001984 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001985 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001986 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001987 int err;
1988
1989 BT_DBG("");
1990
Johan Hedberg06a63b12013-01-20 14:27:21 +02001991 memset(&rp, 0, sizeof(rp));
1992 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1993 rp.addr.type = cp->addr.type;
1994
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001995 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001996 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1997 MGMT_STATUS_INVALID_PARAMS,
1998 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001999
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002000 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002001
2002 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002003 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2004 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002005 goto failed;
2006 }
2007
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002008 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002009 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2010 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002011 goto failed;
2012 }
2013
Andre Guedes591f47f2012-04-24 21:02:49 -03002014 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002015 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2016 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002017 else
2018 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002019
Vishal Agarwalf9607272012-06-13 05:32:43 +05302020 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002021 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2022 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002023 goto failed;
2024 }
2025
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002026 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002027 if (!cmd) {
2028 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002029 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002030 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002031
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002032 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002033 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002034
2035 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2036 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002037 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002038
2039failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002040 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002041 return err;
2042}
2043
Andre Guedes57c14772012-04-24 21:02:50 -03002044static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002045{
2046 switch (link_type) {
2047 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002048 switch (addr_type) {
2049 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002050 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002051
Johan Hedberg48264f02011-11-09 13:58:58 +02002052 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002053 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002054 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002055 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002056
Johan Hedberg4c659c32011-11-07 23:13:39 +02002057 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002058 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002059 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002060 }
2061}
2062
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002063static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2064 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002065{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002066 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002067 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002068 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002069 int err;
2070 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002071
2072 BT_DBG("");
2073
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002074 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002075
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002076 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002077 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002078 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002079 goto unlock;
2080 }
2081
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002082 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002083 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2084 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002085 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002086 }
2087
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002088 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002089 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002090 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002091 err = -ENOMEM;
2092 goto unlock;
2093 }
2094
Johan Hedberg2784eb42011-01-21 13:56:35 +02002095 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002096 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002097 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2098 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002099 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002100 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002101 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002102 continue;
2103 i++;
2104 }
2105
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002106 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002107
Johan Hedberg4c659c32011-11-07 23:13:39 +02002108 /* Recalculate length in case of filtered SCO connections, etc */
2109 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002110
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002111 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002112 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002113
Johan Hedberga38528f2011-01-22 06:46:43 +02002114 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002115
2116unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002117 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002118 return err;
2119}
2120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002121static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002122 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002123{
2124 struct pending_cmd *cmd;
2125 int err;
2126
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002127 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002128 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002129 if (!cmd)
2130 return -ENOMEM;
2131
Johan Hedbergd8457692012-02-17 14:24:57 +02002132 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002133 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002134 if (err < 0)
2135 mgmt_pending_remove(cmd);
2136
2137 return err;
2138}
2139
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002140static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002141 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002143 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002144 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002146 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002147 int err;
2148
2149 BT_DBG("");
2150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002151 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002152
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002153 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002154 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002155 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002156 goto failed;
2157 }
2158
Johan Hedbergd8457692012-02-17 14:24:57 +02002159 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002160 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002161 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002162 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002163 goto failed;
2164 }
2165
2166 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002167 struct mgmt_cp_pin_code_neg_reply ncp;
2168
2169 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002170
2171 BT_ERR("PIN code is not 16 bytes long");
2172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002173 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002174 if (err >= 0)
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_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002177
2178 goto failed;
2179 }
2180
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002181 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002182 if (!cmd) {
2183 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002184 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002185 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002186
Johan Hedbergd8457692012-02-17 14:24:57 +02002187 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002188 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002189 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002190
2191 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2192 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002193 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002194
2195failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002196 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002197 return err;
2198}
2199
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002200static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2201 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002202{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002203 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002204
2205 BT_DBG("");
2206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002207 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002208
2209 hdev->io_capability = cp->io_capability;
2210
2211 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002212 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002213
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002214 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002215
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002216 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2217 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002218}
2219
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002220static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002221{
2222 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002223 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002224
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002225 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002226 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2227 continue;
2228
Johan Hedberge9a416b2011-02-19 12:05:56 -03002229 if (cmd->user_data != conn)
2230 continue;
2231
2232 return cmd;
2233 }
2234
2235 return NULL;
2236}
2237
2238static void pairing_complete(struct pending_cmd *cmd, u8 status)
2239{
2240 struct mgmt_rp_pair_device rp;
2241 struct hci_conn *conn = cmd->user_data;
2242
Johan Hedbergba4e5642011-11-11 00:07:34 +02002243 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002244 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002245
Johan Hedbergaee9b212012-02-18 15:07:59 +02002246 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002247 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002248
2249 /* So we don't get further callbacks for this connection */
2250 conn->connect_cfm_cb = NULL;
2251 conn->security_cfm_cb = NULL;
2252 conn->disconn_cfm_cb = NULL;
2253
David Herrmann76a68ba2013-04-06 20:28:37 +02002254 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002255
Johan Hedberga664b5b2011-02-19 12:06:02 -03002256 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002257}
2258
2259static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2260{
2261 struct pending_cmd *cmd;
2262
2263 BT_DBG("status %u", status);
2264
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002265 cmd = find_pairing(conn);
2266 if (!cmd)
2267 BT_DBG("Unable to find a pending command");
2268 else
Johan Hedberge2113262012-02-18 15:20:03 +02002269 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002270}
2271
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302272static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2273{
2274 struct pending_cmd *cmd;
2275
2276 BT_DBG("status %u", status);
2277
2278 if (!status)
2279 return;
2280
2281 cmd = find_pairing(conn);
2282 if (!cmd)
2283 BT_DBG("Unable to find a pending command");
2284 else
2285 pairing_complete(cmd, mgmt_status(status));
2286}
2287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002288static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002289 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002290{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002291 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002292 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002293 struct pending_cmd *cmd;
2294 u8 sec_level, auth_type;
2295 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002296 int err;
2297
2298 BT_DBG("");
2299
Szymon Jancf950a30e2013-01-18 12:48:07 +01002300 memset(&rp, 0, sizeof(rp));
2301 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2302 rp.addr.type = cp->addr.type;
2303
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002304 if (!bdaddr_type_is_valid(cp->addr.type))
2305 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2306 MGMT_STATUS_INVALID_PARAMS,
2307 &rp, sizeof(rp));
2308
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002309 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002310
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002311 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002312 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2313 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002314 goto unlock;
2315 }
2316
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002317 sec_level = BT_SECURITY_MEDIUM;
2318 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002319 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002320 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002321 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002322
Andre Guedes591f47f2012-04-24 21:02:49 -03002323 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002324 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2325 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002326 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002327 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2328 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002329
Ville Tervo30e76272011-02-22 16:10:53 -03002330 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002331 int status;
2332
2333 if (PTR_ERR(conn) == -EBUSY)
2334 status = MGMT_STATUS_BUSY;
2335 else
2336 status = MGMT_STATUS_CONNECT_FAILED;
2337
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002338 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002339 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002341 goto unlock;
2342 }
2343
2344 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002345 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002346 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002347 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002348 goto unlock;
2349 }
2350
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002351 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002352 if (!cmd) {
2353 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002354 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002355 goto unlock;
2356 }
2357
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002358 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002359 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002360 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302361 else
2362 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002363
Johan Hedberge9a416b2011-02-19 12:05:56 -03002364 conn->security_cfm_cb = pairing_complete_cb;
2365 conn->disconn_cfm_cb = pairing_complete_cb;
2366 conn->io_capability = cp->io_cap;
2367 cmd->user_data = conn;
2368
2369 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002370 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002371 pairing_complete(cmd, 0);
2372
2373 err = 0;
2374
2375unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002376 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002377 return err;
2378}
2379
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002380static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2381 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002382{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002383 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002384 struct pending_cmd *cmd;
2385 struct hci_conn *conn;
2386 int err;
2387
2388 BT_DBG("");
2389
Johan Hedberg28424702012-02-02 04:02:29 +02002390 hci_dev_lock(hdev);
2391
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002392 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002393 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002394 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002395 goto unlock;
2396 }
2397
Johan Hedberg28424702012-02-02 04:02:29 +02002398 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2399 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002400 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002401 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002402 goto unlock;
2403 }
2404
2405 conn = cmd->user_data;
2406
2407 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002408 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002409 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002410 goto unlock;
2411 }
2412
2413 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2414
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002415 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002417unlock:
2418 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002419 return err;
2420}
2421
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002422static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002423 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002425{
Johan Hedberga5c29682011-02-19 12:05:57 -03002426 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002427 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002428 int err;
2429
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002430 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002431
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002432 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002433 err = cmd_complete(sk, hdev->id, mgmt_op,
2434 MGMT_STATUS_NOT_POWERED, addr,
2435 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002436 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002437 }
2438
Johan Hedberg1707c602013-03-15 17:07:15 -05002439 if (addr->type == BDADDR_BREDR)
2440 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002441 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002442 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002443
Johan Hedberg272d90d2012-02-09 15:26:12 +02002444 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002445 err = cmd_complete(sk, hdev->id, mgmt_op,
2446 MGMT_STATUS_NOT_CONNECTED, addr,
2447 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002448 goto done;
2449 }
2450
Johan Hedberg1707c602013-03-15 17:07:15 -05002451 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002452 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002453 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002454
Brian Gix5fe57d92011-12-21 16:12:13 -08002455 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002456 err = cmd_complete(sk, hdev->id, mgmt_op,
2457 MGMT_STATUS_SUCCESS, addr,
2458 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002459 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002460 err = cmd_complete(sk, hdev->id, mgmt_op,
2461 MGMT_STATUS_FAILED, addr,
2462 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002463
Brian Gix47c15e22011-11-16 13:53:14 -08002464 goto done;
2465 }
2466
Johan Hedberg1707c602013-03-15 17:07:15 -05002467 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002468 if (!cmd) {
2469 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002470 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002471 }
2472
Brian Gix0df4c182011-11-16 13:53:13 -08002473 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002474 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2475 struct hci_cp_user_passkey_reply cp;
2476
Johan Hedberg1707c602013-03-15 17:07:15 -05002477 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002478 cp.passkey = passkey;
2479 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2480 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002481 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2482 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002483
Johan Hedberga664b5b2011-02-19 12:06:02 -03002484 if (err < 0)
2485 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002486
Brian Gix0df4c182011-11-16 13:53:13 -08002487done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002488 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002489 return err;
2490}
2491
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302492static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2493 void *data, u16 len)
2494{
2495 struct mgmt_cp_pin_code_neg_reply *cp = data;
2496
2497 BT_DBG("");
2498
Johan Hedberg1707c602013-03-15 17:07:15 -05002499 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302500 MGMT_OP_PIN_CODE_NEG_REPLY,
2501 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2502}
2503
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002504static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2505 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002506{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002508
2509 BT_DBG("");
2510
2511 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002513 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002514
Johan Hedberg1707c602013-03-15 17:07:15 -05002515 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002516 MGMT_OP_USER_CONFIRM_REPLY,
2517 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002518}
2519
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002520static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002521 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002522{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002523 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002524
2525 BT_DBG("");
2526
Johan Hedberg1707c602013-03-15 17:07:15 -05002527 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002528 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2529 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002530}
2531
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2533 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002534{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002535 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002536
2537 BT_DBG("");
2538
Johan Hedberg1707c602013-03-15 17:07:15 -05002539 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002540 MGMT_OP_USER_PASSKEY_REPLY,
2541 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002542}
2543
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002544static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002545 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002546{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002547 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002548
2549 BT_DBG("");
2550
Johan Hedberg1707c602013-03-15 17:07:15 -05002551 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002552 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2553 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002554}
2555
Johan Hedberg13928972013-03-15 17:07:00 -05002556static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002557{
Johan Hedberg13928972013-03-15 17:07:00 -05002558 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002559 struct hci_cp_write_local_name cp;
2560
Johan Hedberg13928972013-03-15 17:07:00 -05002561 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002562
Johan Hedberg890ea892013-03-15 17:06:52 -05002563 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002564}
2565
Johan Hedberg13928972013-03-15 17:07:00 -05002566static void set_name_complete(struct hci_dev *hdev, u8 status)
2567{
2568 struct mgmt_cp_set_local_name *cp;
2569 struct pending_cmd *cmd;
2570
2571 BT_DBG("status 0x%02x", status);
2572
2573 hci_dev_lock(hdev);
2574
2575 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2576 if (!cmd)
2577 goto unlock;
2578
2579 cp = cmd->param;
2580
2581 if (status)
2582 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2583 mgmt_status(status));
2584 else
2585 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2586 cp, sizeof(*cp));
2587
2588 mgmt_pending_remove(cmd);
2589
2590unlock:
2591 hci_dev_unlock(hdev);
2592}
2593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002594static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002595 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002596{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002597 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002598 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002599 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002600 int err;
2601
2602 BT_DBG("");
2603
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002604 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002605
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002606 /* If the old values are the same as the new ones just return a
2607 * direct command complete event.
2608 */
2609 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2610 !memcmp(hdev->short_name, cp->short_name,
2611 sizeof(hdev->short_name))) {
2612 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2613 data, len);
2614 goto failed;
2615 }
2616
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002617 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002618
Johan Hedbergb5235a62012-02-21 14:32:24 +02002619 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002620 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002621
2622 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002623 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002624 if (err < 0)
2625 goto failed;
2626
2627 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002628 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002629
Johan Hedbergb5235a62012-02-21 14:32:24 +02002630 goto failed;
2631 }
2632
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002633 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002634 if (!cmd) {
2635 err = -ENOMEM;
2636 goto failed;
2637 }
2638
Johan Hedberg13928972013-03-15 17:07:00 -05002639 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2640
Johan Hedberg890ea892013-03-15 17:06:52 -05002641 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002642
2643 if (lmp_bredr_capable(hdev)) {
2644 update_name(&req);
2645 update_eir(&req);
2646 }
2647
2648 if (lmp_le_capable(hdev))
2649 hci_update_ad(&req);
2650
Johan Hedberg13928972013-03-15 17:07:00 -05002651 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002652 if (err < 0)
2653 mgmt_pending_remove(cmd);
2654
2655failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002656 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002657 return err;
2658}
2659
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002660static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002662{
Szymon Jancc35938b2011-03-22 13:12:21 +01002663 struct pending_cmd *cmd;
2664 int err;
2665
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002666 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002667
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002668 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002669
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002670 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002671 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002672 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002673 goto unlock;
2674 }
2675
Andre Guedes9a1a1992012-07-24 15:03:48 -03002676 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002677 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002678 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002679 goto unlock;
2680 }
2681
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002682 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002683 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002684 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002685 goto unlock;
2686 }
2687
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002688 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002689 if (!cmd) {
2690 err = -ENOMEM;
2691 goto unlock;
2692 }
2693
2694 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2695 if (err < 0)
2696 mgmt_pending_remove(cmd);
2697
2698unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002699 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002700 return err;
2701}
2702
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002703static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002704 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002705{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002706 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002707 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002708 int err;
2709
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002711
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002712 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002713
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002714 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002715 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002716 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002717 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002718 else
Szymon Janca6785be2012-12-13 15:11:21 +01002719 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002721 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002722 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002723
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002724 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002725 return err;
2726}
2727
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002728static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002729 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002730{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002731 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002732 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002733 int err;
2734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002735 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002736
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002737 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002738
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002739 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002740 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002741 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002742 else
Szymon Janca6785be2012-12-13 15:11:21 +01002743 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002745 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002746 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002747
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002748 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002749 return err;
2750}
2751
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002752static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2753{
2754 struct pending_cmd *cmd;
2755 u8 type;
2756 int err;
2757
2758 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2759
2760 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2761 if (!cmd)
2762 return -ENOENT;
2763
2764 type = hdev->discovery.type;
2765
2766 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2767 &type, sizeof(type));
2768 mgmt_pending_remove(cmd);
2769
2770 return err;
2771}
2772
Andre Guedes7c307722013-04-30 15:29:28 -03002773static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2774{
2775 BT_DBG("status %d", status);
2776
2777 if (status) {
2778 hci_dev_lock(hdev);
2779 mgmt_start_discovery_failed(hdev, status);
2780 hci_dev_unlock(hdev);
2781 return;
2782 }
2783
2784 hci_dev_lock(hdev);
2785 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2786 hci_dev_unlock(hdev);
2787
2788 switch (hdev->discovery.type) {
2789 case DISCOV_TYPE_LE:
2790 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002791 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002792 break;
2793
2794 case DISCOV_TYPE_INTERLEAVED:
2795 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002796 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002797 break;
2798
2799 case DISCOV_TYPE_BREDR:
2800 break;
2801
2802 default:
2803 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2804 }
2805}
2806
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002807static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002808 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002809{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002810 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002811 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002812 struct hci_cp_le_set_scan_param param_cp;
2813 struct hci_cp_le_set_scan_enable enable_cp;
2814 struct hci_cp_inquiry inq_cp;
2815 struct hci_request req;
2816 /* General inquiry access code (GIAC) */
2817 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002818 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002819 int err;
2820
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002821 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002822
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002823 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002824
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002825 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002826 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002827 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002828 goto failed;
2829 }
2830
Andre Guedes642be6c2012-03-21 00:03:37 -03002831 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2832 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2833 MGMT_STATUS_BUSY);
2834 goto failed;
2835 }
2836
Johan Hedbergff9ef572012-01-04 14:23:45 +02002837 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002838 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002839 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002840 goto failed;
2841 }
2842
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002843 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002844 if (!cmd) {
2845 err = -ENOMEM;
2846 goto failed;
2847 }
2848
Andre Guedes4aab14e2012-02-17 20:39:36 -03002849 hdev->discovery.type = cp->type;
2850
Andre Guedes7c307722013-04-30 15:29:28 -03002851 hci_req_init(&req, hdev);
2852
Andre Guedes4aab14e2012-02-17 20:39:36 -03002853 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002854 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002855 status = mgmt_bredr_support(hdev);
2856 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002857 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002858 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002859 mgmt_pending_remove(cmd);
2860 goto failed;
2861 }
2862
Andre Guedes7c307722013-04-30 15:29:28 -03002863 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2864 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2865 MGMT_STATUS_BUSY);
2866 mgmt_pending_remove(cmd);
2867 goto failed;
2868 }
2869
2870 hci_inquiry_cache_flush(hdev);
2871
2872 memset(&inq_cp, 0, sizeof(inq_cp));
2873 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002874 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002875 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002876 break;
2877
2878 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002879 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002880 status = mgmt_le_support(hdev);
2881 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002882 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002883 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002884 mgmt_pending_remove(cmd);
2885 goto failed;
2886 }
2887
Andre Guedes7c307722013-04-30 15:29:28 -03002888 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002889 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002890 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2891 MGMT_STATUS_NOT_SUPPORTED);
2892 mgmt_pending_remove(cmd);
2893 goto failed;
2894 }
2895
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002896 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002897 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2898 MGMT_STATUS_REJECTED);
2899 mgmt_pending_remove(cmd);
2900 goto failed;
2901 }
2902
2903 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2904 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2905 MGMT_STATUS_BUSY);
2906 mgmt_pending_remove(cmd);
2907 goto failed;
2908 }
2909
2910 memset(&param_cp, 0, sizeof(param_cp));
2911 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002912 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2913 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002914 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2915 &param_cp);
2916
2917 memset(&enable_cp, 0, sizeof(enable_cp));
2918 enable_cp.enable = LE_SCAN_ENABLE;
2919 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2920 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2921 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002922 break;
2923
Andre Guedesf39799f2012-02-17 20:39:35 -03002924 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002925 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2926 MGMT_STATUS_INVALID_PARAMS);
2927 mgmt_pending_remove(cmd);
2928 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002929 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002930
Andre Guedes7c307722013-04-30 15:29:28 -03002931 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002932 if (err < 0)
2933 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002934 else
2935 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002936
2937failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002938 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002939 return err;
2940}
2941
Andre Guedes1183fdc2013-04-30 15:29:35 -03002942static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2943{
2944 struct pending_cmd *cmd;
2945 int err;
2946
2947 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2948 if (!cmd)
2949 return -ENOENT;
2950
2951 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2952 &hdev->discovery.type, sizeof(hdev->discovery.type));
2953 mgmt_pending_remove(cmd);
2954
2955 return err;
2956}
2957
Andre Guedes0e05bba2013-04-30 15:29:33 -03002958static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2959{
2960 BT_DBG("status %d", status);
2961
2962 hci_dev_lock(hdev);
2963
2964 if (status) {
2965 mgmt_stop_discovery_failed(hdev, status);
2966 goto unlock;
2967 }
2968
2969 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2970
2971unlock:
2972 hci_dev_unlock(hdev);
2973}
2974
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002975static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002976 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002977{
Johan Hedbergd9306502012-02-20 23:25:18 +02002978 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002979 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002980 struct hci_cp_remote_name_req_cancel cp;
2981 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002982 struct hci_request req;
2983 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002984 int err;
2985
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002986 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002987
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002988 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002989
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002990 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002991 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002992 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2993 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002994 goto unlock;
2995 }
2996
2997 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002998 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002999 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3000 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003001 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003002 }
3003
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003004 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003005 if (!cmd) {
3006 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003007 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003008 }
3009
Andre Guedes0e05bba2013-04-30 15:29:33 -03003010 hci_req_init(&req, hdev);
3011
Andre Guedese0d9727e2012-03-20 15:15:36 -03003012 switch (hdev->discovery.state) {
3013 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003014 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3015 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3016 } else {
3017 cancel_delayed_work(&hdev->le_scan_disable);
3018
3019 memset(&enable_cp, 0, sizeof(enable_cp));
3020 enable_cp.enable = LE_SCAN_DISABLE;
3021 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3022 sizeof(enable_cp), &enable_cp);
3023 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003024
Andre Guedese0d9727e2012-03-20 15:15:36 -03003025 break;
3026
3027 case DISCOVERY_RESOLVING:
3028 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003029 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003030 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003031 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003032 err = cmd_complete(sk, hdev->id,
3033 MGMT_OP_STOP_DISCOVERY, 0,
3034 &mgmt_cp->type,
3035 sizeof(mgmt_cp->type));
3036 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3037 goto unlock;
3038 }
3039
3040 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003041 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3042 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003043
3044 break;
3045
3046 default:
3047 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003048
3049 mgmt_pending_remove(cmd);
3050 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3051 MGMT_STATUS_FAILED, &mgmt_cp->type,
3052 sizeof(mgmt_cp->type));
3053 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003054 }
3055
Andre Guedes0e05bba2013-04-30 15:29:33 -03003056 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003057 if (err < 0)
3058 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003059 else
3060 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003061
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003062unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003063 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003064 return err;
3065}
3066
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003067static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003068 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003069{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003070 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003071 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003072 int err;
3073
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003074 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003075
Johan Hedberg561aafb2012-01-04 13:31:59 +02003076 hci_dev_lock(hdev);
3077
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003078 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003079 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003080 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003081 goto failed;
3082 }
3083
Johan Hedberga198e7b2012-02-17 14:27:06 +02003084 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003085 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003088 goto failed;
3089 }
3090
3091 if (cp->name_known) {
3092 e->name_state = NAME_KNOWN;
3093 list_del(&e->list);
3094 } else {
3095 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003096 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003097 }
3098
Johan Hedberge3846622013-01-09 15:29:33 +02003099 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3100 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003101
3102failed:
3103 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003104 return err;
3105}
3106
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003107static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003108 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003109{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003110 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003111 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003112 int err;
3113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003114 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003115
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003116 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003117 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3118 MGMT_STATUS_INVALID_PARAMS,
3119 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003120
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003121 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003122
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003123 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003124 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003125 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003126 else
Szymon Janca6785be2012-12-13 15:11:21 +01003127 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003128
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003129 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003130 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003131
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003132 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003133
3134 return err;
3135}
3136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003137static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003138 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003139{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003140 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003141 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003142 int err;
3143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003144 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003145
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003146 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003147 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3148 MGMT_STATUS_INVALID_PARAMS,
3149 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003151 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003152
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003153 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003154 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003155 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003156 else
Szymon Janca6785be2012-12-13 15:11:21 +01003157 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003158
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003159 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003160 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003161
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003162 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003163
3164 return err;
3165}
3166
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003167static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3168 u16 len)
3169{
3170 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003171 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003172 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003173 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003174
3175 BT_DBG("%s", hdev->name);
3176
Szymon Jancc72d4b82012-03-16 16:02:57 +01003177 source = __le16_to_cpu(cp->source);
3178
3179 if (source > 0x0002)
3180 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3181 MGMT_STATUS_INVALID_PARAMS);
3182
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003183 hci_dev_lock(hdev);
3184
Szymon Jancc72d4b82012-03-16 16:02:57 +01003185 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003186 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3187 hdev->devid_product = __le16_to_cpu(cp->product);
3188 hdev->devid_version = __le16_to_cpu(cp->version);
3189
3190 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3191
Johan Hedberg890ea892013-03-15 17:06:52 -05003192 hci_req_init(&req, hdev);
3193 update_eir(&req);
3194 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003195
3196 hci_dev_unlock(hdev);
3197
3198 return err;
3199}
3200
Johan Hedberg4375f102013-09-25 13:26:10 +03003201static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3202{
3203 struct cmd_lookup match = { NULL, hdev };
3204
3205 if (status) {
3206 u8 mgmt_err = mgmt_status(status);
3207
3208 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3209 cmd_status_rsp, &mgmt_err);
3210 return;
3211 }
3212
3213 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3214 &match);
3215
3216 new_settings(hdev, match.sk);
3217
3218 if (match.sk)
3219 sock_put(match.sk);
3220}
3221
3222static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3223{
3224 struct mgmt_mode *cp = data;
3225 struct pending_cmd *cmd;
3226 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003227 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003228 int err;
3229
3230 BT_DBG("request for %s", hdev->name);
3231
Johan Hedberge6fe7982013-10-02 15:45:22 +03003232 status = mgmt_le_support(hdev);
3233 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003234 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003235 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003236
3237 if (cp->val != 0x00 && cp->val != 0x01)
3238 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3239 MGMT_STATUS_INVALID_PARAMS);
3240
3241 hci_dev_lock(hdev);
3242
3243 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003244 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003245
3246 if (!hdev_is_powered(hdev) || val == enabled) {
3247 bool changed = false;
3248
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003249 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3250 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003251 changed = true;
3252 }
3253
3254 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3255 if (err < 0)
3256 goto unlock;
3257
3258 if (changed)
3259 err = new_settings(hdev, sk);
3260
3261 goto unlock;
3262 }
3263
3264 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3265 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3266 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3267 MGMT_STATUS_BUSY);
3268 goto unlock;
3269 }
3270
3271 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3272 if (!cmd) {
3273 err = -ENOMEM;
3274 goto unlock;
3275 }
3276
3277 hci_req_init(&req, hdev);
3278
3279 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3280
3281 err = hci_req_run(&req, set_advertising_complete);
3282 if (err < 0)
3283 mgmt_pending_remove(cmd);
3284
3285unlock:
3286 hci_dev_unlock(hdev);
3287 return err;
3288}
3289
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003290static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3291 void *data, u16 len)
3292{
3293 struct mgmt_cp_set_static_address *cp = data;
3294 int err;
3295
3296 BT_DBG("%s", hdev->name);
3297
Marcel Holtmann62af4442013-10-02 22:10:32 -07003298 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003299 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003300 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003301
3302 if (hdev_is_powered(hdev))
3303 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3304 MGMT_STATUS_REJECTED);
3305
3306 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3307 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3308 return cmd_status(sk, hdev->id,
3309 MGMT_OP_SET_STATIC_ADDRESS,
3310 MGMT_STATUS_INVALID_PARAMS);
3311
3312 /* Two most significant bits shall be set */
3313 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3314 return cmd_status(sk, hdev->id,
3315 MGMT_OP_SET_STATIC_ADDRESS,
3316 MGMT_STATUS_INVALID_PARAMS);
3317 }
3318
3319 hci_dev_lock(hdev);
3320
3321 bacpy(&hdev->static_addr, &cp->bdaddr);
3322
3323 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3324
3325 hci_dev_unlock(hdev);
3326
3327 return err;
3328}
3329
Johan Hedberg33e38b32013-03-15 17:07:05 -05003330static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3331{
3332 struct pending_cmd *cmd;
3333
3334 BT_DBG("status 0x%02x", status);
3335
3336 hci_dev_lock(hdev);
3337
3338 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3339 if (!cmd)
3340 goto unlock;
3341
3342 if (status) {
3343 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3344 mgmt_status(status));
3345 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003346 struct mgmt_mode *cp = cmd->param;
3347
3348 if (cp->val)
3349 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3350 else
3351 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3352
Johan Hedberg33e38b32013-03-15 17:07:05 -05003353 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3354 new_settings(hdev, cmd->sk);
3355 }
3356
3357 mgmt_pending_remove(cmd);
3358
3359unlock:
3360 hci_dev_unlock(hdev);
3361}
3362
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003363static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003364 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003365{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003366 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003367 struct pending_cmd *cmd;
3368 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003369 int err;
3370
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003371 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003372
Johan Hedberg56f87902013-10-02 13:43:13 +03003373 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3374 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003375 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3376 MGMT_STATUS_NOT_SUPPORTED);
3377
Johan Hedberga7e80f22013-01-09 16:05:19 +02003378 if (cp->val != 0x00 && cp->val != 0x01)
3379 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3380 MGMT_STATUS_INVALID_PARAMS);
3381
Johan Hedberg5400c042012-02-21 16:40:33 +02003382 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003383 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003384 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003385
3386 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003387 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003388 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003389
3390 hci_dev_lock(hdev);
3391
Johan Hedberg05cbf292013-03-15 17:07:07 -05003392 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3393 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3394 MGMT_STATUS_BUSY);
3395 goto unlock;
3396 }
3397
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003398 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3399 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3400 hdev);
3401 goto unlock;
3402 }
3403
Johan Hedberg33e38b32013-03-15 17:07:05 -05003404 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3405 data, len);
3406 if (!cmd) {
3407 err = -ENOMEM;
3408 goto unlock;
3409 }
3410
3411 hci_req_init(&req, hdev);
3412
Johan Hedberg406d7802013-03-15 17:07:09 -05003413 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003414
3415 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003416 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003417 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003418 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003419 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003420 }
3421
Johan Hedberg33e38b32013-03-15 17:07:05 -05003422unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003423 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003424
Antti Julkuf6422ec2011-06-22 13:11:56 +03003425 return err;
3426}
3427
Johan Hedberg0663ca22013-10-02 13:43:14 +03003428static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3429{
3430 struct pending_cmd *cmd;
3431
3432 BT_DBG("status 0x%02x", status);
3433
3434 hci_dev_lock(hdev);
3435
3436 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3437 if (!cmd)
3438 goto unlock;
3439
3440 if (status) {
3441 u8 mgmt_err = mgmt_status(status);
3442
3443 /* We need to restore the flag if related HCI commands
3444 * failed.
3445 */
3446 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3447
3448 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3449 } else {
3450 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3451 new_settings(hdev, cmd->sk);
3452 }
3453
3454 mgmt_pending_remove(cmd);
3455
3456unlock:
3457 hci_dev_unlock(hdev);
3458}
3459
3460static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3461{
3462 struct mgmt_mode *cp = data;
3463 struct pending_cmd *cmd;
3464 struct hci_request req;
3465 int err;
3466
3467 BT_DBG("request for %s", hdev->name);
3468
3469 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3470 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3471 MGMT_STATUS_NOT_SUPPORTED);
3472
3473 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3474 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3475 MGMT_STATUS_REJECTED);
3476
3477 if (cp->val != 0x00 && cp->val != 0x01)
3478 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3479 MGMT_STATUS_INVALID_PARAMS);
3480
3481 hci_dev_lock(hdev);
3482
3483 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3484 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3485 goto unlock;
3486 }
3487
3488 if (!hdev_is_powered(hdev)) {
3489 if (!cp->val) {
3490 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3491 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3492 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3493 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3494 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3495 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3496 }
3497
3498 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3499
3500 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3501 if (err < 0)
3502 goto unlock;
3503
3504 err = new_settings(hdev, sk);
3505 goto unlock;
3506 }
3507
3508 /* Reject disabling when powered on */
3509 if (!cp->val) {
3510 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3511 MGMT_STATUS_REJECTED);
3512 goto unlock;
3513 }
3514
3515 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3516 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3517 MGMT_STATUS_BUSY);
3518 goto unlock;
3519 }
3520
3521 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3522 if (!cmd) {
3523 err = -ENOMEM;
3524 goto unlock;
3525 }
3526
3527 /* We need to flip the bit already here so that hci_update_ad
3528 * generates the correct flags.
3529 */
3530 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3531
3532 hci_req_init(&req, hdev);
3533 hci_update_ad(&req);
3534 err = hci_req_run(&req, set_bredr_complete);
3535 if (err < 0)
3536 mgmt_pending_remove(cmd);
3537
3538unlock:
3539 hci_dev_unlock(hdev);
3540 return err;
3541}
3542
Johan Hedberg3f706b72013-01-20 14:27:16 +02003543static bool ltk_is_valid(struct mgmt_ltk_info *key)
3544{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003545 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3546 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003547 if (key->master != 0x00 && key->master != 0x01)
3548 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003549 if (!bdaddr_type_is_le(key->addr.type))
3550 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003551 return true;
3552}
3553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003554static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003555 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003556{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003557 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3558 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003559 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003560
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003561 BT_DBG("request for %s", hdev->name);
3562
3563 if (!lmp_le_capable(hdev))
3564 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3565 MGMT_STATUS_NOT_SUPPORTED);
3566
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003567 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003568
3569 expected_len = sizeof(*cp) + key_count *
3570 sizeof(struct mgmt_ltk_info);
3571 if (expected_len != len) {
3572 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003573 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003574 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003575 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003576 }
3577
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003578 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003579
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003580 for (i = 0; i < key_count; i++) {
3581 struct mgmt_ltk_info *key = &cp->keys[i];
3582
Johan Hedberg3f706b72013-01-20 14:27:16 +02003583 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003584 return cmd_status(sk, hdev->id,
3585 MGMT_OP_LOAD_LONG_TERM_KEYS,
3586 MGMT_STATUS_INVALID_PARAMS);
3587 }
3588
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003589 hci_dev_lock(hdev);
3590
3591 hci_smp_ltks_clear(hdev);
3592
3593 for (i = 0; i < key_count; i++) {
3594 struct mgmt_ltk_info *key = &cp->keys[i];
3595 u8 type;
3596
3597 if (key->master)
3598 type = HCI_SMP_LTK;
3599 else
3600 type = HCI_SMP_LTK_SLAVE;
3601
Hemant Gupta4596fde2012-04-16 14:57:40 +05303602 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003603 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003604 type, 0, key->authenticated, key->val,
3605 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003606 }
3607
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003608 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3609 NULL, 0);
3610
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003611 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003612
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003613 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003614}
3615
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003616static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003617 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3618 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003619 bool var_len;
3620 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003621} mgmt_handlers[] = {
3622 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003623 { read_version, false, MGMT_READ_VERSION_SIZE },
3624 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3625 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3626 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3627 { set_powered, false, MGMT_SETTING_SIZE },
3628 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3629 { set_connectable, false, MGMT_SETTING_SIZE },
3630 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3631 { set_pairable, false, MGMT_SETTING_SIZE },
3632 { set_link_security, false, MGMT_SETTING_SIZE },
3633 { set_ssp, false, MGMT_SETTING_SIZE },
3634 { set_hs, false, MGMT_SETTING_SIZE },
3635 { set_le, false, MGMT_SETTING_SIZE },
3636 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3637 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3638 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3639 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3640 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3641 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3642 { disconnect, false, MGMT_DISCONNECT_SIZE },
3643 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3644 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3645 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3646 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3647 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3648 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3649 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3650 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3651 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3652 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3653 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3654 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3655 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3656 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3657 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3658 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3659 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3660 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3661 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003662 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003663 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003664 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003665 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003666};
3667
3668
Johan Hedberg03811012010-12-08 00:21:06 +02003669int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3670{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003671 void *buf;
3672 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003673 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003674 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003675 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003676 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003677 int err;
3678
3679 BT_DBG("got %zu bytes", msglen);
3680
3681 if (msglen < sizeof(*hdr))
3682 return -EINVAL;
3683
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003684 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003685 if (!buf)
3686 return -ENOMEM;
3687
3688 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3689 err = -EFAULT;
3690 goto done;
3691 }
3692
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003693 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003694 opcode = __le16_to_cpu(hdr->opcode);
3695 index = __le16_to_cpu(hdr->index);
3696 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003697
3698 if (len != msglen - sizeof(*hdr)) {
3699 err = -EINVAL;
3700 goto done;
3701 }
3702
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003703 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003704 hdev = hci_dev_get(index);
3705 if (!hdev) {
3706 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003707 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003708 goto done;
3709 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003710
3711 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3712 err = cmd_status(sk, index, opcode,
3713 MGMT_STATUS_INVALID_INDEX);
3714 goto done;
3715 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003716 }
3717
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003718 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003719 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003720 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003721 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003722 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003723 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003724 }
3725
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003726 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003727 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003728 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003729 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003730 goto done;
3731 }
3732
Johan Hedbergbe22b542012-03-01 22:24:41 +02003733 handler = &mgmt_handlers[opcode];
3734
3735 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003736 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003737 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003738 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003739 goto done;
3740 }
3741
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003742 if (hdev)
3743 mgmt_init_hdev(sk, hdev);
3744
3745 cp = buf + sizeof(*hdr);
3746
Johan Hedbergbe22b542012-03-01 22:24:41 +02003747 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003748 if (err < 0)
3749 goto done;
3750
Johan Hedberg03811012010-12-08 00:21:06 +02003751 err = msglen;
3752
3753done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003754 if (hdev)
3755 hci_dev_put(hdev);
3756
Johan Hedberg03811012010-12-08 00:21:06 +02003757 kfree(buf);
3758 return err;
3759}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003760
Johan Hedberg744cf192011-11-08 20:40:14 +02003761int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003762{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003763 if (!mgmt_valid_hdev(hdev))
3764 return -ENOTSUPP;
3765
Johan Hedberg744cf192011-11-08 20:40:14 +02003766 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003767}
3768
Johan Hedberg744cf192011-11-08 20:40:14 +02003769int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003770{
Johan Hedberg5f159032012-03-02 03:13:19 +02003771 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003772
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003773 if (!mgmt_valid_hdev(hdev))
3774 return -ENOTSUPP;
3775
Johan Hedberg744cf192011-11-08 20:40:14 +02003776 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003777
Johan Hedberg744cf192011-11-08 20:40:14 +02003778 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003779}
3780
Johan Hedberg890ea892013-03-15 17:06:52 -05003781static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003782{
Johan Hedberg890ea892013-03-15 17:06:52 -05003783 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003784 u8 scan = 0;
3785
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003786 /* Ensure that fast connectable is disabled. This function will
3787 * not do anything if the page scan parameters are already what
3788 * they should be.
3789 */
3790 write_fast_connectable(req, false);
3791
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003792 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3793 scan |= SCAN_PAGE;
3794 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3795 scan |= SCAN_INQUIRY;
3796
Johan Hedberg890ea892013-03-15 17:06:52 -05003797 if (scan)
3798 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003799}
3800
Johan Hedberg229ab392013-03-15 17:06:53 -05003801static void powered_complete(struct hci_dev *hdev, u8 status)
3802{
3803 struct cmd_lookup match = { NULL, hdev };
3804
3805 BT_DBG("status 0x%02x", status);
3806
3807 hci_dev_lock(hdev);
3808
3809 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3810
3811 new_settings(hdev, match.sk);
3812
3813 hci_dev_unlock(hdev);
3814
3815 if (match.sk)
3816 sock_put(match.sk);
3817}
3818
Johan Hedberg70da6242013-03-15 17:06:51 -05003819static int powered_update_hci(struct hci_dev *hdev)
3820{
Johan Hedberg890ea892013-03-15 17:06:52 -05003821 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003822 u8 link_sec;
3823
Johan Hedberg890ea892013-03-15 17:06:52 -05003824 hci_req_init(&req, hdev);
3825
Johan Hedberg70da6242013-03-15 17:06:51 -05003826 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3827 !lmp_host_ssp_capable(hdev)) {
3828 u8 ssp = 1;
3829
Johan Hedberg890ea892013-03-15 17:06:52 -05003830 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003831 }
3832
Johan Hedbergc73eee92013-04-19 18:35:21 +03003833 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3834 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003835 struct hci_cp_write_le_host_supported cp;
3836
3837 cp.le = 1;
3838 cp.simul = lmp_le_br_capable(hdev);
3839
3840 /* Check first if we already have the right
3841 * host state (host features set)
3842 */
3843 if (cp.le != lmp_host_le_capable(hdev) ||
3844 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003845 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3846 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003847
3848 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3849 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003850 }
3851
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003852 if (lmp_le_capable(hdev)) {
3853 /* Set random address to static address if configured */
3854 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3855 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3856 &hdev->static_addr);
3857 }
3858
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003859 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003860 u8 adv = 0x01;
3861
3862 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3863 }
3864
Johan Hedberg70da6242013-03-15 17:06:51 -05003865 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3866 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003867 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3868 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003869
3870 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003871 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3872 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003873 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003874 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003875 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003876 }
3877
Johan Hedberg229ab392013-03-15 17:06:53 -05003878 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003879}
3880
Johan Hedberg744cf192011-11-08 20:40:14 +02003881int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003882{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003883 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003884 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3885 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003886 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003887
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003888 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3889 return 0;
3890
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003891 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003892 if (powered_update_hci(hdev) == 0)
3893 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003894
Johan Hedberg229ab392013-03-15 17:06:53 -05003895 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3896 &match);
3897 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003898 }
3899
Johan Hedberg229ab392013-03-15 17:06:53 -05003900 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3901 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3902
3903 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3904 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3905 zero_cod, sizeof(zero_cod), NULL);
3906
3907new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003908 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003909
3910 if (match.sk)
3911 sock_put(match.sk);
3912
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003913 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003914}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003915
Johan Hedberg96570ff2013-05-29 09:51:29 +03003916int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3917{
3918 struct pending_cmd *cmd;
3919 u8 status;
3920
3921 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3922 if (!cmd)
3923 return -ENOENT;
3924
3925 if (err == -ERFKILL)
3926 status = MGMT_STATUS_RFKILLED;
3927 else
3928 status = MGMT_STATUS_FAILED;
3929
3930 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3931
3932 mgmt_pending_remove(cmd);
3933
3934 return err;
3935}
3936
Johan Hedberg744cf192011-11-08 20:40:14 +02003937int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003938{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003939 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003940 bool changed = false;
3941 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003942
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003943 if (discoverable) {
3944 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3945 changed = true;
3946 } else {
3947 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3948 changed = true;
3949 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003950
Johan Hedberged9b5f22012-02-21 20:47:06 +02003951 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003952 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003953
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003954 if (changed)
3955 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003956
Johan Hedberg73f22f62010-12-29 16:00:25 +02003957 if (match.sk)
3958 sock_put(match.sk);
3959
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003960 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003961}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003962
Johan Hedberg744cf192011-11-08 20:40:14 +02003963int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003964{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003965 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003966 bool changed = false;
3967 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003968
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003969 if (connectable) {
3970 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3971 changed = true;
3972 } else {
3973 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3974 changed = true;
3975 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003976
Johan Hedberg2b76f452013-03-15 17:07:04 -05003977 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003978
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003979 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003980 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003981
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003982 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003983}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003984
Johan Hedberg744cf192011-11-08 20:40:14 +02003985int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003986{
Johan Hedbergca69b792011-11-11 18:10:00 +02003987 u8 mgmt_err = mgmt_status(status);
3988
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003989 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003990 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003991 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003992
3993 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003994 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003995 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003996
3997 return 0;
3998}
3999
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004000int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4001 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004002{
Johan Hedberg86742e12011-11-07 23:13:38 +02004003 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004004
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004005 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004006
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004007 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004008 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004009 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004010 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004011 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004012 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004013
Johan Hedberg744cf192011-11-08 20:40:14 +02004014 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004015}
Johan Hedbergf7520542011-01-20 12:34:39 +02004016
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004017int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4018{
4019 struct mgmt_ev_new_long_term_key ev;
4020
4021 memset(&ev, 0, sizeof(ev));
4022
4023 ev.store_hint = persistent;
4024 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004025 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004026 ev.key.authenticated = key->authenticated;
4027 ev.key.enc_size = key->enc_size;
4028 ev.key.ediv = key->ediv;
4029
4030 if (key->type == HCI_SMP_LTK)
4031 ev.key.master = 1;
4032
4033 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4034 memcpy(ev.key.val, key->val, sizeof(key->val));
4035
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004036 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4037 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004038}
4039
Johan Hedbergafc747a2012-01-15 18:11:07 +02004040int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004041 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4042 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004043{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004044 char buf[512];
4045 struct mgmt_ev_device_connected *ev = (void *) buf;
4046 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004047
Johan Hedbergb644ba32012-01-17 21:48:47 +02004048 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004049 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004050
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004051 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004052
Johan Hedbergb644ba32012-01-17 21:48:47 +02004053 if (name_len > 0)
4054 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004055 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004056
4057 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004058 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004059 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004060
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004061 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004062
4063 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004064 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004065}
4066
Johan Hedberg8962ee72011-01-20 12:40:27 +02004067static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4068{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004069 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004070 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004071 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004072
Johan Hedberg88c3df12012-02-09 14:27:38 +02004073 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4074 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004075
Johan Hedbergaee9b212012-02-18 15:07:59 +02004076 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004077 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004078
4079 *sk = cmd->sk;
4080 sock_hold(*sk);
4081
Johan Hedberga664b5b2011-02-19 12:06:02 -03004082 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004083}
4084
Johan Hedberg124f6e32012-02-09 13:50:12 +02004085static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004086{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004087 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004088 struct mgmt_cp_unpair_device *cp = cmd->param;
4089 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004090
4091 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004092 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4093 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004094
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004095 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4096
Johan Hedbergaee9b212012-02-18 15:07:59 +02004097 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004098
4099 mgmt_pending_remove(cmd);
4100}
4101
Johan Hedbergafc747a2012-01-15 18:11:07 +02004102int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004103 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004104{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004105 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004106 struct sock *sk = NULL;
4107 int err;
4108
Johan Hedberg744cf192011-11-08 20:40:14 +02004109 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004110
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004111 bacpy(&ev.addr.bdaddr, bdaddr);
4112 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4113 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004114
Johan Hedbergafc747a2012-01-15 18:11:07 +02004115 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004116 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004117
4118 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004119 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004120
Johan Hedberg124f6e32012-02-09 13:50:12 +02004121 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004122 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004123
Johan Hedberg8962ee72011-01-20 12:40:27 +02004124 return err;
4125}
4126
Johan Hedberg88c3df12012-02-09 14:27:38 +02004127int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004128 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004129{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004130 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004131 struct pending_cmd *cmd;
4132 int err;
4133
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004134 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4135 hdev);
4136
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004137 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004138 if (!cmd)
4139 return -ENOENT;
4140
Johan Hedberg88c3df12012-02-09 14:27:38 +02004141 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004142 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004143
Johan Hedberg88c3df12012-02-09 14:27:38 +02004144 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004145 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004146
Johan Hedberga664b5b2011-02-19 12:06:02 -03004147 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004148
4149 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004150}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004151
Johan Hedberg48264f02011-11-09 13:58:58 +02004152int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004153 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004154{
4155 struct mgmt_ev_connect_failed ev;
4156
Johan Hedberg4c659c32011-11-07 23:13:39 +02004157 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004158 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004159 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004160
Johan Hedberg744cf192011-11-08 20:40:14 +02004161 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004162}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004163
Johan Hedberg744cf192011-11-08 20:40:14 +02004164int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004165{
4166 struct mgmt_ev_pin_code_request ev;
4167
Johan Hedbergd8457692012-02-17 14:24:57 +02004168 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004169 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004170 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004171
Johan Hedberg744cf192011-11-08 20:40:14 +02004172 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004173 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004174}
4175
Johan Hedberg744cf192011-11-08 20:40:14 +02004176int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004177 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004178{
4179 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004180 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004181 int err;
4182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004183 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004184 if (!cmd)
4185 return -ENOENT;
4186
Johan Hedbergd8457692012-02-17 14:24:57 +02004187 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004188 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004189
Johan Hedbergaee9b212012-02-18 15:07:59 +02004190 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004191 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004192
Johan Hedberga664b5b2011-02-19 12:06:02 -03004193 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004194
4195 return err;
4196}
4197
Johan Hedberg744cf192011-11-08 20:40:14 +02004198int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004199 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004200{
4201 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004202 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004203 int err;
4204
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004205 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004206 if (!cmd)
4207 return -ENOENT;
4208
Johan Hedbergd8457692012-02-17 14:24:57 +02004209 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004210 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004211
Johan Hedbergaee9b212012-02-18 15:07:59 +02004212 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004213 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004214
Johan Hedberga664b5b2011-02-19 12:06:02 -03004215 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004216
4217 return err;
4218}
Johan Hedberga5c29682011-02-19 12:05:57 -03004219
Johan Hedberg744cf192011-11-08 20:40:14 +02004220int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004221 u8 link_type, u8 addr_type, __le32 value,
4222 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004223{
4224 struct mgmt_ev_user_confirm_request ev;
4225
Johan Hedberg744cf192011-11-08 20:40:14 +02004226 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004227
Johan Hedberg272d90d2012-02-09 15:26:12 +02004228 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004229 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004230 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004231 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004232
Johan Hedberg744cf192011-11-08 20:40:14 +02004233 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004234 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004235}
4236
Johan Hedberg272d90d2012-02-09 15:26:12 +02004237int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004238 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004239{
4240 struct mgmt_ev_user_passkey_request ev;
4241
4242 BT_DBG("%s", hdev->name);
4243
Johan Hedberg272d90d2012-02-09 15:26:12 +02004244 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004245 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004246
4247 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004248 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004249}
4250
Brian Gix0df4c182011-11-16 13:53:13 -08004251static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004252 u8 link_type, u8 addr_type, u8 status,
4253 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004254{
4255 struct pending_cmd *cmd;
4256 struct mgmt_rp_user_confirm_reply rp;
4257 int err;
4258
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004259 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004260 if (!cmd)
4261 return -ENOENT;
4262
Johan Hedberg272d90d2012-02-09 15:26:12 +02004263 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004264 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004265 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004266 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004267
Johan Hedberga664b5b2011-02-19 12:06:02 -03004268 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004269
4270 return err;
4271}
4272
Johan Hedberg744cf192011-11-08 20:40:14 +02004273int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004274 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004275{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004276 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004277 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004278}
4279
Johan Hedberg272d90d2012-02-09 15:26:12 +02004280int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004281 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004282{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004283 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004284 status,
4285 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004286}
Johan Hedberg2a611692011-02-19 12:06:00 -03004287
Brian Gix604086b2011-11-23 08:28:33 -08004288int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004289 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004290{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004291 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004292 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004293}
4294
Johan Hedberg272d90d2012-02-09 15:26:12 +02004295int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004296 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004297{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004298 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004299 status,
4300 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004301}
4302
Johan Hedberg92a25252012-09-06 18:39:26 +03004303int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4304 u8 link_type, u8 addr_type, u32 passkey,
4305 u8 entered)
4306{
4307 struct mgmt_ev_passkey_notify ev;
4308
4309 BT_DBG("%s", hdev->name);
4310
4311 bacpy(&ev.addr.bdaddr, bdaddr);
4312 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4313 ev.passkey = __cpu_to_le32(passkey);
4314 ev.entered = entered;
4315
4316 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4317}
4318
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004319int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004320 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004321{
4322 struct mgmt_ev_auth_failed ev;
4323
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004324 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004325 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004326 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004327
Johan Hedberg744cf192011-11-08 20:40:14 +02004328 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004329}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004330
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004331int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4332{
4333 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004334 bool changed = false;
4335 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004336
4337 if (status) {
4338 u8 mgmt_err = mgmt_status(status);
4339 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004340 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004341 return 0;
4342 }
4343
Johan Hedberg47990ea2012-02-22 11:58:37 +02004344 if (test_bit(HCI_AUTH, &hdev->flags)) {
4345 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4346 changed = true;
4347 } else {
4348 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4349 changed = true;
4350 }
4351
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004352 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004353 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004354
Johan Hedberg47990ea2012-02-22 11:58:37 +02004355 if (changed)
4356 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004357
4358 if (match.sk)
4359 sock_put(match.sk);
4360
4361 return err;
4362}
4363
Johan Hedberg890ea892013-03-15 17:06:52 -05004364static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004365{
Johan Hedberg890ea892013-03-15 17:06:52 -05004366 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004367 struct hci_cp_write_eir cp;
4368
Johan Hedberg976eb202012-10-24 21:12:01 +03004369 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004370 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004371
Johan Hedbergc80da272012-02-22 15:38:48 +02004372 memset(hdev->eir, 0, sizeof(hdev->eir));
4373
Johan Hedbergcacaf522012-02-21 00:52:42 +02004374 memset(&cp, 0, sizeof(cp));
4375
Johan Hedberg890ea892013-03-15 17:06:52 -05004376 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004377}
4378
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004379int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004380{
4381 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004382 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004383 bool changed = false;
4384 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004385
4386 if (status) {
4387 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004388
4389 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004390 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004391 err = new_settings(hdev, NULL);
4392
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004393 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4394 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004395
4396 return err;
4397 }
4398
4399 if (enable) {
4400 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4401 changed = true;
4402 } else {
4403 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4404 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004405 }
4406
4407 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4408
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004409 if (changed)
4410 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004411
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004412 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004413 sock_put(match.sk);
4414
Johan Hedberg890ea892013-03-15 17:06:52 -05004415 hci_req_init(&req, hdev);
4416
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004417 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004418 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004419 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004420 clear_eir(&req);
4421
4422 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004423
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004424 return err;
4425}
4426
Johan Hedberg92da6092013-03-15 17:06:55 -05004427static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004428{
4429 struct cmd_lookup *match = data;
4430
Johan Hedberg90e70452012-02-23 23:09:40 +02004431 if (match->sk == NULL) {
4432 match->sk = cmd->sk;
4433 sock_hold(match->sk);
4434 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004435}
4436
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004437int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004438 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004439{
Johan Hedberg90e70452012-02-23 23:09:40 +02004440 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4441 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004442
Johan Hedberg92da6092013-03-15 17:06:55 -05004443 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4444 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4445 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004446
4447 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004448 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4449 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004450
4451 if (match.sk)
4452 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004453
4454 return err;
4455}
4456
Johan Hedberg744cf192011-11-08 20:40:14 +02004457int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004458{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004459 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004460 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004461
Johan Hedberg13928972013-03-15 17:07:00 -05004462 if (status)
4463 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004464
4465 memset(&ev, 0, sizeof(ev));
4466 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004467 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004468
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004469 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004470 if (!cmd) {
4471 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004472
Johan Hedberg13928972013-03-15 17:07:00 -05004473 /* If this is a HCI command related to powering on the
4474 * HCI dev don't send any mgmt signals.
4475 */
4476 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4477 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004478 }
4479
Johan Hedberg13928972013-03-15 17:07:00 -05004480 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4481 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004482}
Szymon Jancc35938b2011-03-22 13:12:21 +01004483
Johan Hedberg744cf192011-11-08 20:40:14 +02004484int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004485 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004486{
4487 struct pending_cmd *cmd;
4488 int err;
4489
Johan Hedberg744cf192011-11-08 20:40:14 +02004490 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004491
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004492 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004493 if (!cmd)
4494 return -ENOENT;
4495
4496 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004497 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4498 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004499 } else {
4500 struct mgmt_rp_read_local_oob_data rp;
4501
4502 memcpy(rp.hash, hash, sizeof(rp.hash));
4503 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4504
Johan Hedberg744cf192011-11-08 20:40:14 +02004505 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004506 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4507 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004508 }
4509
4510 mgmt_pending_remove(cmd);
4511
4512 return err;
4513}
Johan Hedberge17acd42011-03-30 23:57:16 +03004514
Johan Hedberg48264f02011-11-09 13:58:58 +02004515int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004516 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4517 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004518{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004519 char buf[512];
4520 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004521 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004522
Andre Guedes12602d02013-04-30 15:29:40 -03004523 if (!hci_discovery_active(hdev))
4524 return -EPERM;
4525
Johan Hedberg1dc06092012-01-15 21:01:23 +02004526 /* Leave 5 bytes for a potential CoD field */
4527 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004528 return -EINVAL;
4529
Johan Hedberg1dc06092012-01-15 21:01:23 +02004530 memset(buf, 0, sizeof(buf));
4531
Johan Hedberge319d2e2012-01-15 19:51:59 +02004532 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004533 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004534 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004535 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304536 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004537 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304538 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004539
Johan Hedberg1dc06092012-01-15 21:01:23 +02004540 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004541 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004542
Johan Hedberg1dc06092012-01-15 21:01:23 +02004543 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4544 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004545 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004546
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004547 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004548 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004549
Johan Hedberge319d2e2012-01-15 19:51:59 +02004550 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004551}
Johan Hedberga88a9652011-03-30 13:18:12 +03004552
Johan Hedbergb644ba32012-01-17 21:48:47 +02004553int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004554 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004555{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004556 struct mgmt_ev_device_found *ev;
4557 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4558 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004559
Johan Hedbergb644ba32012-01-17 21:48:47 +02004560 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004561
Johan Hedbergb644ba32012-01-17 21:48:47 +02004562 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004563
Johan Hedbergb644ba32012-01-17 21:48:47 +02004564 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004565 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004566 ev->rssi = rssi;
4567
4568 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004569 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004570
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004571 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004572
Johan Hedberg053c7e02012-02-04 00:06:00 +02004573 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004574 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004575}
Johan Hedberg314b2382011-04-27 10:29:57 -04004576
Johan Hedberg744cf192011-11-08 20:40:14 +02004577int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004578{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004579 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004580 struct pending_cmd *cmd;
4581
Andre Guedes343fb142011-11-22 17:14:19 -03004582 BT_DBG("%s discovering %u", hdev->name, discovering);
4583
Johan Hedberg164a6e72011-11-01 17:06:44 +02004584 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004585 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004586 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004587 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004588
4589 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004590 u8 type = hdev->discovery.type;
4591
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004592 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4593 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004594 mgmt_pending_remove(cmd);
4595 }
4596
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004597 memset(&ev, 0, sizeof(ev));
4598 ev.type = hdev->discovery.type;
4599 ev.discovering = discovering;
4600
4601 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004602}
Antti Julku5e762442011-08-25 16:48:02 +03004603
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004604int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004605{
4606 struct pending_cmd *cmd;
4607 struct mgmt_ev_device_blocked ev;
4608
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004609 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004610
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004611 bacpy(&ev.addr.bdaddr, bdaddr);
4612 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004613
Johan Hedberg744cf192011-11-08 20:40:14 +02004614 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004615 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004616}
4617
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004618int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004619{
4620 struct pending_cmd *cmd;
4621 struct mgmt_ev_device_unblocked ev;
4622
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004623 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004624
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004625 bacpy(&ev.addr.bdaddr, bdaddr);
4626 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004627
Johan Hedberg744cf192011-11-08 20:40:14 +02004628 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004629 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004630}