blob: 4ac31695946b9f3e3eaf9539b82a318af9d5dfbb [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
Johan Hedberg38102852013-01-27 08:32:01 -060036#define MGMT_REVISION 3
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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800105#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200106
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200107#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
108 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
109
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200110struct pending_cmd {
111 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200112 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100114 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200115 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300116 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117};
118
Johan Hedbergca69b792011-11-11 18:10:00 +0200119/* HCI to MGMT error code conversion table */
120static u8 mgmt_status_table[] = {
121 MGMT_STATUS_SUCCESS,
122 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
123 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
124 MGMT_STATUS_FAILED, /* Hardware Failure */
125 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
126 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
127 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
128 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
129 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
130 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
132 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
133 MGMT_STATUS_BUSY, /* Command Disallowed */
134 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
135 MGMT_STATUS_REJECTED, /* Rejected Security */
136 MGMT_STATUS_REJECTED, /* Rejected Personal */
137 MGMT_STATUS_TIMEOUT, /* Host Timeout */
138 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
139 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
140 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
141 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
142 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
143 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
144 MGMT_STATUS_BUSY, /* Repeated Attempts */
145 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
146 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
147 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
148 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
149 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
150 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
151 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
152 MGMT_STATUS_FAILED, /* Unspecified Error */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
154 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
155 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
156 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
157 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
158 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
159 MGMT_STATUS_FAILED, /* Unit Link Key Used */
160 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
161 MGMT_STATUS_TIMEOUT, /* Instant Passed */
162 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
163 MGMT_STATUS_FAILED, /* Transaction Collision */
164 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
165 MGMT_STATUS_REJECTED, /* QoS Rejected */
166 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
167 MGMT_STATUS_REJECTED, /* Insufficient Security */
168 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
169 MGMT_STATUS_BUSY, /* Role Switch Pending */
170 MGMT_STATUS_FAILED, /* Slot Violation */
171 MGMT_STATUS_FAILED, /* Role Switch Failed */
172 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
173 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
174 MGMT_STATUS_BUSY, /* Host Busy Pairing */
175 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
176 MGMT_STATUS_BUSY, /* Controller Busy */
177 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
178 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
179 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
180 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
181 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
182};
183
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300184bool mgmt_valid_hdev(struct hci_dev *hdev)
185{
186 return hdev->dev_type == HCI_BREDR;
187}
188
Johan Hedbergca69b792011-11-11 18:10:00 +0200189static u8 mgmt_status(u8 hci_status)
190{
191 if (hci_status < ARRAY_SIZE(mgmt_status_table))
192 return mgmt_status_table[hci_status];
193
194 return MGMT_STATUS_FAILED;
195}
196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200198{
199 struct sk_buff *skb;
200 struct mgmt_hdr *hdr;
201 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300202 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Szymon Janc34eb5252011-02-28 14:10:08 +0100204 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205
Andre Guedes790eff42012-06-07 19:05:46 -0300206 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207 if (!skb)
208 return -ENOMEM;
209
210 hdr = (void *) skb_put(skb, sizeof(*hdr));
211
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530212 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100213 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214 hdr->len = cpu_to_le16(sizeof(*ev));
215
216 ev = (void *) skb_put(skb, sizeof(*ev));
217 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200218 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200219
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300220 err = sock_queue_rcv_skb(sk, skb);
221 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200222 kfree_skb(skb);
223
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300224 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200225}
226
Johan Hedbergaee9b212012-02-18 15:07:59 +0200227static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300228 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200229{
230 struct sk_buff *skb;
231 struct mgmt_hdr *hdr;
232 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200234
235 BT_DBG("sock %p", sk);
236
Andre Guedes790eff42012-06-07 19:05:46 -0300237 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200238 if (!skb)
239 return -ENOMEM;
240
241 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200242
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530243 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100244 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200248 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200249 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100250
251 if (rp)
252 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200253
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300254 err = sock_queue_rcv_skb(sk, skb);
255 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200256 kfree_skb(skb);
257
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100258 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200259}
260
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300261static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
262 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200263{
264 struct mgmt_rp_read_version rp;
265
266 BT_DBG("sock %p", sk);
267
268 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200269 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200270
Johan Hedbergaee9b212012-02-18 15:07:59 +0200271 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300272 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200273}
274
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300275static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
276 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200277{
278 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200279 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
280 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200281 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200282 size_t rp_size;
283 int i, err;
284
285 BT_DBG("sock %p", sk);
286
287 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
288
289 rp = kmalloc(rp_size, GFP_KERNEL);
290 if (!rp)
291 return -ENOMEM;
292
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200293 rp->num_commands = __constant_cpu_to_le16(num_commands);
294 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295
296 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
297 put_unaligned_le16(mgmt_commands[i], opcode);
298
299 for (i = 0; i < num_events; i++, opcode++)
300 put_unaligned_le16(mgmt_events[i], opcode);
301
Johan Hedbergaee9b212012-02-18 15:07:59 +0200302 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300303 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304 kfree(rp);
305
306 return err;
307}
308
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300309static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
310 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200313 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200314 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300316 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200317
318 BT_DBG("sock %p", sk);
319
320 read_lock(&hci_dev_list_lock);
321
322 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300323 list_for_each_entry(d, &hci_dev_list, list) {
324 if (!mgmt_valid_hdev(d))
325 continue;
326
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 count++;
328 }
329
Johan Hedberga38528f2011-01-22 06:46:43 +0200330 rp_len = sizeof(*rp) + (2 * count);
331 rp = kmalloc(rp_len, GFP_ATOMIC);
332 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100333 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200334 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100335 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200336
Johan Hedberg476e44c2012-10-19 20:10:46 +0300337 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200339 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200340 continue;
341
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700342 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
343 continue;
344
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300345 if (!mgmt_valid_hdev(d))
346 continue;
347
Johan Hedberg476e44c2012-10-19 20:10:46 +0300348 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 BT_DBG("Added hci%u", d->id);
350 }
351
Johan Hedberg476e44c2012-10-19 20:10:46 +0300352 rp->num_controllers = cpu_to_le16(count);
353 rp_len = sizeof(*rp) + (2 * count);
354
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b212012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Andre Guedes9a1a1992012-07-24 15:03:48 -0300372 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Andre Guedesed3fa312012-07-24 15:03:46 -0300375 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300376 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500377 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
378 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300379 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380 settings |= MGMT_SETTING_BREDR;
381 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100382 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700383 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300385 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200386 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300387 settings |= MGMT_SETTING_ADVERTISING;
388 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200389
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200390 return settings;
391}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200392
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200393static u32 get_current_settings(struct hci_dev *hdev)
394{
395 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200396
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200397 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 settings |= MGMT_SETTING_POWERED;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_CONNECTABLE;
402
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500403 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
404 settings |= MGMT_SETTING_FAST_CONNECTABLE;
405
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200406 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_DISCOVERABLE;
408
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200409 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_PAIRABLE;
411
Johan Hedberg56f87902013-10-02 13:43:13 +0300412 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_BREDR;
414
Johan Hedberg06199cf2012-02-22 16:37:11 +0200415 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200417
Johan Hedberg47990ea2012-02-22 11:58:37 +0200418 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200420
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200421 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200424 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
425 settings |= MGMT_SETTING_HS;
426
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300427 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
428 settings |= MGMT_SETTING_ADVERTISING;
429
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200430 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200431}
432
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300433#define PNP_INFO_SVCLASS_ID 0x1200
434
Johan Hedberg213202e2013-01-27 00:31:33 +0200435static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
436{
437 u8 *ptr = data, *uuids_start = NULL;
438 struct bt_uuid *uuid;
439
440 if (len < 4)
441 return ptr;
442
443 list_for_each_entry(uuid, &hdev->uuids, list) {
444 u16 uuid16;
445
446 if (uuid->size != 16)
447 continue;
448
449 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
450 if (uuid16 < 0x1100)
451 continue;
452
453 if (uuid16 == PNP_INFO_SVCLASS_ID)
454 continue;
455
456 if (!uuids_start) {
457 uuids_start = ptr;
458 uuids_start[0] = 1;
459 uuids_start[1] = EIR_UUID16_ALL;
460 ptr += 2;
461 }
462
463 /* Stop if not enough space to put next UUID */
464 if ((ptr - data) + sizeof(u16) > len) {
465 uuids_start[1] = EIR_UUID16_SOME;
466 break;
467 }
468
469 *ptr++ = (uuid16 & 0x00ff);
470 *ptr++ = (uuid16 & 0xff00) >> 8;
471 uuids_start[0] += sizeof(uuid16);
472 }
473
474 return ptr;
475}
476
Johan Hedbergcdf19632013-01-27 00:31:34 +0200477static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
478{
479 u8 *ptr = data, *uuids_start = NULL;
480 struct bt_uuid *uuid;
481
482 if (len < 6)
483 return ptr;
484
485 list_for_each_entry(uuid, &hdev->uuids, list) {
486 if (uuid->size != 32)
487 continue;
488
489 if (!uuids_start) {
490 uuids_start = ptr;
491 uuids_start[0] = 1;
492 uuids_start[1] = EIR_UUID32_ALL;
493 ptr += 2;
494 }
495
496 /* Stop if not enough space to put next UUID */
497 if ((ptr - data) + sizeof(u32) > len) {
498 uuids_start[1] = EIR_UUID32_SOME;
499 break;
500 }
501
502 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
503 ptr += sizeof(u32);
504 uuids_start[0] += sizeof(u32);
505 }
506
507 return ptr;
508}
509
Johan Hedbergc00d5752013-01-27 00:31:35 +0200510static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
511{
512 u8 *ptr = data, *uuids_start = NULL;
513 struct bt_uuid *uuid;
514
515 if (len < 18)
516 return ptr;
517
518 list_for_each_entry(uuid, &hdev->uuids, list) {
519 if (uuid->size != 128)
520 continue;
521
522 if (!uuids_start) {
523 uuids_start = ptr;
524 uuids_start[0] = 1;
525 uuids_start[1] = EIR_UUID128_ALL;
526 ptr += 2;
527 }
528
529 /* Stop if not enough space to put next UUID */
530 if ((ptr - data) + 16 > len) {
531 uuids_start[1] = EIR_UUID128_SOME;
532 break;
533 }
534
535 memcpy(ptr, uuid->uuid, 16);
536 ptr += 16;
537 uuids_start[0] += 16;
538 }
539
540 return ptr;
541}
542
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300543static void create_eir(struct hci_dev *hdev, u8 *data)
544{
545 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300546 size_t name_len;
547
548 name_len = strlen(hdev->dev_name);
549
550 if (name_len > 0) {
551 /* EIR Data type */
552 if (name_len > 48) {
553 name_len = 48;
554 ptr[1] = EIR_NAME_SHORT;
555 } else
556 ptr[1] = EIR_NAME_COMPLETE;
557
558 /* EIR Data length */
559 ptr[0] = name_len + 1;
560
561 memcpy(ptr + 2, hdev->dev_name, name_len);
562
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300563 ptr += (name_len + 2);
564 }
565
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100566 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700567 ptr[0] = 2;
568 ptr[1] = EIR_TX_POWER;
569 ptr[2] = (u8) hdev->inq_tx_power;
570
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700571 ptr += 3;
572 }
573
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700574 if (hdev->devid_source > 0) {
575 ptr[0] = 9;
576 ptr[1] = EIR_DEVICE_ID;
577
578 put_unaligned_le16(hdev->devid_source, ptr + 2);
579 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
580 put_unaligned_le16(hdev->devid_product, ptr + 6);
581 put_unaligned_le16(hdev->devid_version, ptr + 8);
582
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700583 ptr += 10;
584 }
585
Johan Hedberg213202e2013-01-27 00:31:33 +0200586 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200587 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200588 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300589}
590
Johan Hedberg890ea892013-03-15 17:06:52 -0500591static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300592{
Johan Hedberg890ea892013-03-15 17:06:52 -0500593 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300594 struct hci_cp_write_eir cp;
595
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200596 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500597 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200598
Johan Hedberg976eb202012-10-24 21:12:01 +0300599 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200602 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500603 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300604
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200605 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500606 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300607
608 memset(&cp, 0, sizeof(cp));
609
610 create_eir(hdev, cp.data);
611
612 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500613 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300614
615 memcpy(hdev->eir, cp.data, sizeof(cp.data));
616
Johan Hedberg890ea892013-03-15 17:06:52 -0500617 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300618}
619
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620static u8 get_service_classes(struct hci_dev *hdev)
621{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300622 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200623 u8 val = 0;
624
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300625 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200626 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627
628 return val;
629}
630
Johan Hedberg890ea892013-03-15 17:06:52 -0500631static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200632{
Johan Hedberg890ea892013-03-15 17:06:52 -0500633 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200634 u8 cod[3];
635
636 BT_DBG("%s", hdev->name);
637
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200638 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500639 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200640
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200641 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500642 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200643
644 cod[0] = hdev->minor_class;
645 cod[1] = hdev->major_class;
646 cod[2] = get_service_classes(hdev);
647
648 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500649 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200650
Johan Hedberg890ea892013-03-15 17:06:52 -0500651 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200652}
653
Johan Hedberg7d785252011-12-15 00:47:39 +0200654static void service_cache_off(struct work_struct *work)
655{
656 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300657 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500658 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200659
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200660 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200661 return;
662
Johan Hedberg890ea892013-03-15 17:06:52 -0500663 hci_req_init(&req, hdev);
664
Johan Hedberg7d785252011-12-15 00:47:39 +0200665 hci_dev_lock(hdev);
666
Johan Hedberg890ea892013-03-15 17:06:52 -0500667 update_eir(&req);
668 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200669
670 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500671
672 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200673}
674
Johan Hedberg6a919082012-02-28 06:17:26 +0200675static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200676{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200677 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200678 return;
679
Johan Hedberg4f87da82012-03-02 19:55:56 +0200680 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200681
Johan Hedberg4f87da82012-03-02 19:55:56 +0200682 /* Non-mgmt controlled devices get this bit set
683 * implicitly so that pairing works for them, however
684 * for mgmt we require user-space to explicitly enable
685 * it
686 */
687 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200688}
689
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200690static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300691 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200692{
693 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200694
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200695 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300697 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200698
Johan Hedberg03811012010-12-08 00:21:06 +0200699 memset(&rp, 0, sizeof(rp));
700
Johan Hedberg03811012010-12-08 00:21:06 +0200701 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200702
703 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200704 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200705
706 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
707 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
708
709 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200710
711 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200712 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200713
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300714 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200715
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200716 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300717 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200718}
719
720static void mgmt_pending_free(struct pending_cmd *cmd)
721{
722 sock_put(cmd->sk);
723 kfree(cmd->param);
724 kfree(cmd);
725}
726
727static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300728 struct hci_dev *hdev, void *data,
729 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200730{
731 struct pending_cmd *cmd;
732
Andre Guedes12b94562012-06-07 19:05:45 -0300733 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200734 if (!cmd)
735 return NULL;
736
737 cmd->opcode = opcode;
738 cmd->index = hdev->id;
739
Andre Guedes12b94562012-06-07 19:05:45 -0300740 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200741 if (!cmd->param) {
742 kfree(cmd);
743 return NULL;
744 }
745
746 if (data)
747 memcpy(cmd->param, data, len);
748
749 cmd->sk = sk;
750 sock_hold(sk);
751
752 list_add(&cmd->list, &hdev->mgmt_pending);
753
754 return cmd;
755}
756
757static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300758 void (*cb)(struct pending_cmd *cmd,
759 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300760 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200761{
Andre Guedesa3d09352013-02-01 11:21:30 -0300762 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200763
Andre Guedesa3d09352013-02-01 11:21:30 -0300764 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200765 if (opcode > 0 && cmd->opcode != opcode)
766 continue;
767
768 cb(cmd, data);
769 }
770}
771
772static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
773{
774 struct pending_cmd *cmd;
775
776 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
777 if (cmd->opcode == opcode)
778 return cmd;
779 }
780
781 return NULL;
782}
783
784static void mgmt_pending_remove(struct pending_cmd *cmd)
785{
786 list_del(&cmd->list);
787 mgmt_pending_free(cmd);
788}
789
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200790static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200791{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200792 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200793
Johan Hedbergaee9b212012-02-18 15:07:59 +0200794 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300795 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200796}
797
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200798static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300799 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200800{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300801 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200802 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200803 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200804
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200805 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200806
Johan Hedberga7e80f22013-01-09 16:05:19 +0200807 if (cp->val != 0x00 && cp->val != 0x01)
808 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
809 MGMT_STATUS_INVALID_PARAMS);
810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300811 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200812
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300813 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
814 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
815 MGMT_STATUS_BUSY);
816 goto failed;
817 }
818
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100819 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
820 cancel_delayed_work(&hdev->power_off);
821
822 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200823 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
824 data, len);
825 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100826 goto failed;
827 }
828 }
829
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200830 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200831 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200832 goto failed;
833 }
834
Johan Hedberg03811012010-12-08 00:21:06 +0200835 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
836 if (!cmd) {
837 err = -ENOMEM;
838 goto failed;
839 }
840
841 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200842 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200843 else
Johan Hedberg19202572013-01-14 22:33:51 +0200844 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200845
846 err = 0;
847
848failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300849 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200850 return err;
851}
852
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300853static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
854 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200855{
856 struct sk_buff *skb;
857 struct mgmt_hdr *hdr;
858
Andre Guedes790eff42012-06-07 19:05:46 -0300859 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200860 if (!skb)
861 return -ENOMEM;
862
863 hdr = (void *) skb_put(skb, sizeof(*hdr));
864 hdr->opcode = cpu_to_le16(event);
865 if (hdev)
866 hdr->index = cpu_to_le16(hdev->id);
867 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530868 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200869 hdr->len = cpu_to_le16(data_len);
870
871 if (data)
872 memcpy(skb_put(skb, data_len), data, data_len);
873
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100874 /* Time stamp */
875 __net_timestamp(skb);
876
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200877 hci_send_to_control(skb, skip_sk);
878 kfree_skb(skb);
879
880 return 0;
881}
882
883static int new_settings(struct hci_dev *hdev, struct sock *skip)
884{
885 __le32 ev;
886
887 ev = cpu_to_le32(get_current_settings(hdev));
888
889 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
890}
891
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300892struct cmd_lookup {
893 struct sock *sk;
894 struct hci_dev *hdev;
895 u8 mgmt_status;
896};
897
898static void settings_rsp(struct pending_cmd *cmd, void *data)
899{
900 struct cmd_lookup *match = data;
901
902 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
903
904 list_del(&cmd->list);
905
906 if (match->sk == NULL) {
907 match->sk = cmd->sk;
908 sock_hold(match->sk);
909 }
910
911 mgmt_pending_free(cmd);
912}
913
914static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
915{
916 u8 *status = data;
917
918 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
919 mgmt_pending_remove(cmd);
920}
921
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200922static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300923 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200924{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300925 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200926 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200927 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200928 u8 scan;
929 int err;
930
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200931 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200932
Johan Hedberg56f87902013-10-02 13:43:13 +0300933 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +0300934 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
935 MGMT_STATUS_NOT_SUPPORTED);
936
Johan Hedberga7e80f22013-01-09 16:05:19 +0200937 if (cp->val != 0x00 && cp->val != 0x01)
938 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
939 MGMT_STATUS_INVALID_PARAMS);
940
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700941 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100942 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200943 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300944 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200945
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300946 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200947
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200948 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200949 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300950 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200951 goto failed;
952 }
953
954 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300955 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200956 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300957 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200958 goto failed;
959 }
960
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200961 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200962 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300963 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200964 goto failed;
965 }
966
967 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200968 bool changed = false;
969
970 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
971 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
972 changed = true;
973 }
974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200976 if (err < 0)
977 goto failed;
978
979 if (changed)
980 err = new_settings(hdev, sk);
981
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200982 goto failed;
983 }
984
985 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100986 if (hdev->discov_timeout > 0) {
987 cancel_delayed_work(&hdev->discov_off);
988 hdev->discov_timeout = 0;
989 }
990
991 if (cp->val && timeout > 0) {
992 hdev->discov_timeout = timeout;
993 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
994 msecs_to_jiffies(hdev->discov_timeout * 1000));
995 }
996
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200997 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200998 goto failed;
999 }
1000
1001 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1002 if (!cmd) {
1003 err = -ENOMEM;
1004 goto failed;
1005 }
1006
1007 scan = SCAN_PAGE;
1008
1009 if (cp->val)
1010 scan |= SCAN_INQUIRY;
1011 else
1012 cancel_delayed_work(&hdev->discov_off);
1013
1014 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1015 if (err < 0)
1016 mgmt_pending_remove(cmd);
1017
Johan Hedberg03811012010-12-08 00:21:06 +02001018 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001019 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001020
1021failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001022 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001023 return err;
1024}
1025
Johan Hedberg406d7802013-03-15 17:07:09 -05001026static void write_fast_connectable(struct hci_request *req, bool enable)
1027{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001028 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001029 struct hci_cp_write_page_scan_activity acp;
1030 u8 type;
1031
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001032 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1033 return;
1034
Johan Hedberg406d7802013-03-15 17:07:09 -05001035 if (enable) {
1036 type = PAGE_SCAN_TYPE_INTERLACED;
1037
1038 /* 160 msec page scan interval */
1039 acp.interval = __constant_cpu_to_le16(0x0100);
1040 } else {
1041 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1042
1043 /* default 1.28 sec page scan */
1044 acp.interval = __constant_cpu_to_le16(0x0800);
1045 }
1046
1047 acp.window = __constant_cpu_to_le16(0x0012);
1048
Johan Hedbergbd98b992013-03-15 17:07:13 -05001049 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1050 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1051 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1052 sizeof(acp), &acp);
1053
1054 if (hdev->page_scan_type != type)
1055 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001056}
1057
Johan Hedberg2b76f452013-03-15 17:07:04 -05001058static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1059{
1060 struct pending_cmd *cmd;
1061
1062 BT_DBG("status 0x%02x", status);
1063
1064 hci_dev_lock(hdev);
1065
1066 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1067 if (!cmd)
1068 goto unlock;
1069
1070 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1071
1072 mgmt_pending_remove(cmd);
1073
1074unlock:
1075 hci_dev_unlock(hdev);
1076}
1077
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001078static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001079 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001080{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001081 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001082 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001083 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001084 u8 scan;
1085 int err;
1086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001087 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001088
Johan Hedberg56f87902013-10-02 13:43:13 +03001089 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001090 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1091 MGMT_STATUS_NOT_SUPPORTED);
1092
Johan Hedberga7e80f22013-01-09 16:05:19 +02001093 if (cp->val != 0x00 && cp->val != 0x01)
1094 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1095 MGMT_STATUS_INVALID_PARAMS);
1096
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001097 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001098
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001099 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001100 bool changed = false;
1101
1102 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1103 changed = true;
1104
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001105 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001106 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001107 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001108 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1109 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1110 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001111
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001112 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001113 if (err < 0)
1114 goto failed;
1115
1116 if (changed)
1117 err = new_settings(hdev, sk);
1118
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001119 goto failed;
1120 }
1121
1122 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001123 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001124 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001125 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001126 goto failed;
1127 }
1128
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001129 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001130 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001131 goto failed;
1132 }
1133
1134 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1135 if (!cmd) {
1136 err = -ENOMEM;
1137 goto failed;
1138 }
1139
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001140 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001141 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001142 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001143 scan = 0;
1144
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001145 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001146 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001147 cancel_delayed_work(&hdev->discov_off);
1148 }
1149
Johan Hedberg2b76f452013-03-15 17:07:04 -05001150 hci_req_init(&req, hdev);
1151
1152 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1153
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001154 /* If we're going from non-connectable to connectable or
1155 * vice-versa when fast connectable is enabled ensure that fast
1156 * connectable gets disabled. write_fast_connectable won't do
1157 * anything if the page scan parameters are already what they
1158 * should be.
1159 */
1160 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001161 write_fast_connectable(&req, false);
1162
Johan Hedberg2b76f452013-03-15 17:07:04 -05001163 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001164 if (err < 0)
1165 mgmt_pending_remove(cmd);
1166
1167failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001168 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001169 return err;
1170}
1171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001172static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001173 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001174{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001175 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001176 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001179
Johan Hedberga7e80f22013-01-09 16:05:19 +02001180 if (cp->val != 0x00 && cp->val != 0x01)
1181 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1182 MGMT_STATUS_INVALID_PARAMS);
1183
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001184 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001185
1186 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001187 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001188 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001189 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001190
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001191 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192 if (err < 0)
1193 goto failed;
1194
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001195 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196
1197failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001198 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001199 return err;
1200}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001201
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001202static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1203 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001204{
1205 struct mgmt_mode *cp = data;
1206 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001207 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001208 int err;
1209
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001210 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001211
Johan Hedberg56f87902013-10-02 13:43:13 +03001212 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001213 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1214 MGMT_STATUS_NOT_SUPPORTED);
1215
Johan Hedberga7e80f22013-01-09 16:05:19 +02001216 if (cp->val != 0x00 && cp->val != 0x01)
1217 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1218 MGMT_STATUS_INVALID_PARAMS);
1219
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001220 hci_dev_lock(hdev);
1221
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001222 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001223 bool changed = false;
1224
1225 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001226 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001227 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1228 changed = true;
1229 }
1230
1231 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1232 if (err < 0)
1233 goto failed;
1234
1235 if (changed)
1236 err = new_settings(hdev, sk);
1237
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001238 goto failed;
1239 }
1240
1241 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001242 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001243 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001244 goto failed;
1245 }
1246
1247 val = !!cp->val;
1248
1249 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1250 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1251 goto failed;
1252 }
1253
1254 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1255 if (!cmd) {
1256 err = -ENOMEM;
1257 goto failed;
1258 }
1259
1260 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1261 if (err < 0) {
1262 mgmt_pending_remove(cmd);
1263 goto failed;
1264 }
1265
1266failed:
1267 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001268 return err;
1269}
1270
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001271static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001272{
1273 struct mgmt_mode *cp = data;
1274 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001275 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001276 int err;
1277
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001278 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001279
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001280 if (!lmp_ssp_capable(hdev))
1281 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1282 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001283
Johan Hedberga7e80f22013-01-09 16:05:19 +02001284 if (cp->val != 0x00 && cp->val != 0x01)
1285 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1286 MGMT_STATUS_INVALID_PARAMS);
1287
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001288 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001289
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001290 val = !!cp->val;
1291
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001292 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001293 bool changed = false;
1294
1295 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1296 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1297 changed = true;
1298 }
1299
1300 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1301 if (err < 0)
1302 goto failed;
1303
1304 if (changed)
1305 err = new_settings(hdev, sk);
1306
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001307 goto failed;
1308 }
1309
1310 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001311 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1312 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001313 goto failed;
1314 }
1315
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001316 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1317 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1318 goto failed;
1319 }
1320
1321 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1322 if (!cmd) {
1323 err = -ENOMEM;
1324 goto failed;
1325 }
1326
1327 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1328 if (err < 0) {
1329 mgmt_pending_remove(cmd);
1330 goto failed;
1331 }
1332
1333failed:
1334 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001335 return err;
1336}
1337
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001338static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001339{
1340 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001341 bool changed;
1342 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001343
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001344 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001345
Johan Hedberg56f87902013-10-02 13:43:13 +03001346 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001347 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001348 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001349
Johan Hedberga7e80f22013-01-09 16:05:19 +02001350 if (cp->val != 0x00 && cp->val != 0x01)
1351 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1352 MGMT_STATUS_INVALID_PARAMS);
1353
Marcel Holtmannee392692013-10-01 22:59:23 -07001354 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001355
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001356 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001357 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001358 } else {
1359 if (hdev_is_powered(hdev)) {
1360 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1361 MGMT_STATUS_REJECTED);
1362 goto unlock;
1363 }
1364
Marcel Holtmannee392692013-10-01 22:59:23 -07001365 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001366 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001367
1368 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1369 if (err < 0)
1370 goto unlock;
1371
1372 if (changed)
1373 err = new_settings(hdev, sk);
1374
1375unlock:
1376 hci_dev_unlock(hdev);
1377 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001378}
1379
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001380static void le_enable_complete(struct hci_dev *hdev, u8 status)
1381{
1382 struct cmd_lookup match = { NULL, hdev };
1383
1384 if (status) {
1385 u8 mgmt_err = mgmt_status(status);
1386
1387 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1388 &mgmt_err);
1389 return;
1390 }
1391
1392 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1393
1394 new_settings(hdev, match.sk);
1395
1396 if (match.sk)
1397 sock_put(match.sk);
1398}
1399
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001400static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001401{
1402 struct mgmt_mode *cp = data;
1403 struct hci_cp_write_le_host_supported hci_cp;
1404 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001405 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001406 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001407 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001408
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001409 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001410
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001411 if (!lmp_le_capable(hdev))
1412 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1413 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001414
Johan Hedberga7e80f22013-01-09 16:05:19 +02001415 if (cp->val != 0x00 && cp->val != 0x01)
1416 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1417 MGMT_STATUS_INVALID_PARAMS);
1418
Johan Hedbergc73eee92013-04-19 18:35:21 +03001419 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001420 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001421 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1422 MGMT_STATUS_REJECTED);
1423
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001424 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001425
1426 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001427 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001428
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001429 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001430 bool changed = false;
1431
1432 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1433 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1434 changed = true;
1435 }
1436
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001437 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1438 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1439 changed = true;
1440 }
1441
Johan Hedberg06199cf2012-02-22 16:37:11 +02001442 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1443 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001444 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001445
1446 if (changed)
1447 err = new_settings(hdev, sk);
1448
Johan Hedberg1de028c2012-02-29 19:55:35 -08001449 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001450 }
1451
Johan Hedberg4375f102013-09-25 13:26:10 +03001452 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1453 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001454 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001455 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001456 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001457 }
1458
1459 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1460 if (!cmd) {
1461 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001462 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001463 }
1464
1465 memset(&hci_cp, 0, sizeof(hci_cp));
1466
1467 if (val) {
1468 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001469 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001470 }
1471
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001472 hci_req_init(&req, hdev);
1473
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001474 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1475 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1476
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001477 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1478 &hci_cp);
1479
1480 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301481 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001482 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001483
Johan Hedberg1de028c2012-02-29 19:55:35 -08001484unlock:
1485 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001486 return err;
1487}
1488
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001489/* This is a helper function to test for pending mgmt commands that can
1490 * cause CoD or EIR HCI commands. We can only allow one such pending
1491 * mgmt command at a time since otherwise we cannot easily track what
1492 * the current values are, will be, and based on that calculate if a new
1493 * HCI command needs to be sent and if yes with what value.
1494 */
1495static bool pending_eir_or_class(struct hci_dev *hdev)
1496{
1497 struct pending_cmd *cmd;
1498
1499 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1500 switch (cmd->opcode) {
1501 case MGMT_OP_ADD_UUID:
1502 case MGMT_OP_REMOVE_UUID:
1503 case MGMT_OP_SET_DEV_CLASS:
1504 case MGMT_OP_SET_POWERED:
1505 return true;
1506 }
1507 }
1508
1509 return false;
1510}
1511
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001512static const u8 bluetooth_base_uuid[] = {
1513 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1514 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1515};
1516
1517static u8 get_uuid_size(const u8 *uuid)
1518{
1519 u32 val;
1520
1521 if (memcmp(uuid, bluetooth_base_uuid, 12))
1522 return 128;
1523
1524 val = get_unaligned_le32(&uuid[12]);
1525 if (val > 0xffff)
1526 return 32;
1527
1528 return 16;
1529}
1530
Johan Hedberg92da6092013-03-15 17:06:55 -05001531static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1532{
1533 struct pending_cmd *cmd;
1534
1535 hci_dev_lock(hdev);
1536
1537 cmd = mgmt_pending_find(mgmt_op, hdev);
1538 if (!cmd)
1539 goto unlock;
1540
1541 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1542 hdev->dev_class, 3);
1543
1544 mgmt_pending_remove(cmd);
1545
1546unlock:
1547 hci_dev_unlock(hdev);
1548}
1549
1550static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1551{
1552 BT_DBG("status 0x%02x", status);
1553
1554 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1555}
1556
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001557static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001558{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001559 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001560 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001561 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001562 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001563 int err;
1564
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001565 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001566
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001567 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001568
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001569 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001570 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001571 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001572 goto failed;
1573 }
1574
Andre Guedes92c4c202012-06-07 19:05:44 -03001575 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001576 if (!uuid) {
1577 err = -ENOMEM;
1578 goto failed;
1579 }
1580
1581 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001582 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001583 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001584
Johan Hedbergde66aa62013-01-27 00:31:27 +02001585 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001586
Johan Hedberg890ea892013-03-15 17:06:52 -05001587 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001588
Johan Hedberg890ea892013-03-15 17:06:52 -05001589 update_class(&req);
1590 update_eir(&req);
1591
Johan Hedberg92da6092013-03-15 17:06:55 -05001592 err = hci_req_run(&req, add_uuid_complete);
1593 if (err < 0) {
1594 if (err != -ENODATA)
1595 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001596
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001597 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001598 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001599 goto failed;
1600 }
1601
1602 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001603 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001604 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001605 goto failed;
1606 }
1607
1608 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001609
1610failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001611 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001612 return err;
1613}
1614
Johan Hedberg24b78d02012-02-23 23:24:30 +02001615static bool enable_service_cache(struct hci_dev *hdev)
1616{
1617 if (!hdev_is_powered(hdev))
1618 return false;
1619
1620 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001621 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1622 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001623 return true;
1624 }
1625
1626 return false;
1627}
1628
Johan Hedberg92da6092013-03-15 17:06:55 -05001629static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1630{
1631 BT_DBG("status 0x%02x", status);
1632
1633 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1634}
1635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001636static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001637 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001638{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001639 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001640 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001641 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001642 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 -05001643 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001644 int err, found;
1645
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001646 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001647
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001648 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001649
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001650 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001651 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001652 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001653 goto unlock;
1654 }
1655
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001656 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1657 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001658
Johan Hedberg24b78d02012-02-23 23:24:30 +02001659 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001660 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001661 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001662 goto unlock;
1663 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001664
Johan Hedberg9246a862012-02-23 21:33:16 +02001665 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001666 }
1667
1668 found = 0;
1669
Johan Hedberg056341c2013-01-27 00:31:30 +02001670 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001671 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1672 continue;
1673
1674 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001675 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001676 found++;
1677 }
1678
1679 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001680 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001681 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001682 goto unlock;
1683 }
1684
Johan Hedberg9246a862012-02-23 21:33:16 +02001685update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001686 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001687
Johan Hedberg890ea892013-03-15 17:06:52 -05001688 update_class(&req);
1689 update_eir(&req);
1690
Johan Hedberg92da6092013-03-15 17:06:55 -05001691 err = hci_req_run(&req, remove_uuid_complete);
1692 if (err < 0) {
1693 if (err != -ENODATA)
1694 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001695
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001696 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001697 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001698 goto unlock;
1699 }
1700
1701 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001702 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001703 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001704 goto unlock;
1705 }
1706
1707 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001708
1709unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001710 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001711 return err;
1712}
1713
Johan Hedberg92da6092013-03-15 17:06:55 -05001714static void set_class_complete(struct hci_dev *hdev, u8 status)
1715{
1716 BT_DBG("status 0x%02x", status);
1717
1718 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1719}
1720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001721static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001723{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001724 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001725 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001726 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001727 int err;
1728
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001729 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001730
Johan Hedberg56f87902013-10-02 13:43:13 +03001731 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001732 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1733 MGMT_STATUS_NOT_SUPPORTED);
1734
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001735 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001736
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001737 if (pending_eir_or_class(hdev)) {
1738 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1739 MGMT_STATUS_BUSY);
1740 goto unlock;
1741 }
1742
1743 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1744 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1745 MGMT_STATUS_INVALID_PARAMS);
1746 goto unlock;
1747 }
1748
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001749 hdev->major_class = cp->major;
1750 hdev->minor_class = cp->minor;
1751
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001752 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001753 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001754 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001755 goto unlock;
1756 }
1757
Johan Hedberg890ea892013-03-15 17:06:52 -05001758 hci_req_init(&req, hdev);
1759
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001760 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001761 hci_dev_unlock(hdev);
1762 cancel_delayed_work_sync(&hdev->service_cache);
1763 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001764 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001765 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001766
Johan Hedberg890ea892013-03-15 17:06:52 -05001767 update_class(&req);
1768
Johan Hedberg92da6092013-03-15 17:06:55 -05001769 err = hci_req_run(&req, set_class_complete);
1770 if (err < 0) {
1771 if (err != -ENODATA)
1772 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001773
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001774 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001775 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001776 goto unlock;
1777 }
1778
1779 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001780 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001781 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001782 goto unlock;
1783 }
1784
1785 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001786
Johan Hedbergb5235a62012-02-21 14:32:24 +02001787unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001788 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001789 return err;
1790}
1791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001792static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001793 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001794{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001795 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001796 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001797 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001798
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001799 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001800
Johan Hedberg86742e12011-11-07 23:13:38 +02001801 expected_len = sizeof(*cp) + key_count *
1802 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001803 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001804 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001805 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001806 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001807 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001808 }
1809
Johan Hedberg4ae14302013-01-20 14:27:13 +02001810 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1811 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1812 MGMT_STATUS_INVALID_PARAMS);
1813
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001814 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001815 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001816
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001817 for (i = 0; i < key_count; i++) {
1818 struct mgmt_link_key_info *key = &cp->keys[i];
1819
1820 if (key->addr.type != BDADDR_BREDR)
1821 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1822 MGMT_STATUS_INVALID_PARAMS);
1823 }
1824
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001825 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001826
1827 hci_link_keys_clear(hdev);
1828
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001829 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001830 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001831 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001832 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001833
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001834 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001835 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001836
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001837 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001838 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001839 }
1840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001842
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001843 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001844
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001845 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001846}
1847
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001848static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001849 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001850{
1851 struct mgmt_ev_device_unpaired ev;
1852
1853 bacpy(&ev.addr.bdaddr, bdaddr);
1854 ev.addr.type = addr_type;
1855
1856 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001857 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001858}
1859
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001860static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001861 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001862{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001863 struct mgmt_cp_unpair_device *cp = data;
1864 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001865 struct hci_cp_disconnect dc;
1866 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001867 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001868 int err;
1869
Johan Hedberga8a1d192011-11-10 15:54:38 +02001870 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001871 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1872 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001873
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001874 if (!bdaddr_type_is_valid(cp->addr.type))
1875 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1876 MGMT_STATUS_INVALID_PARAMS,
1877 &rp, sizeof(rp));
1878
Johan Hedberg118da702013-01-20 14:27:20 +02001879 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1880 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1881 MGMT_STATUS_INVALID_PARAMS,
1882 &rp, sizeof(rp));
1883
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001884 hci_dev_lock(hdev);
1885
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001886 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001887 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001888 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001889 goto unlock;
1890 }
1891
Andre Guedes591f47f2012-04-24 21:02:49 -03001892 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001893 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1894 else
1895 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001896
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001897 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001898 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001899 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001900 goto unlock;
1901 }
1902
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001903 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001904 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001905 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001906 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001907 else
1908 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001909 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001910 } else {
1911 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001912 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001913
Johan Hedberga8a1d192011-11-10 15:54:38 +02001914 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001915 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001916 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001917 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001918 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001919 }
1920
Johan Hedberg124f6e32012-02-09 13:50:12 +02001921 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001922 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001923 if (!cmd) {
1924 err = -ENOMEM;
1925 goto unlock;
1926 }
1927
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001928 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001929 dc.reason = 0x13; /* Remote User Terminated Connection */
1930 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1931 if (err < 0)
1932 mgmt_pending_remove(cmd);
1933
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001934unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001935 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001936 return err;
1937}
1938
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001939static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001940 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001941{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001942 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001943 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001944 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001945 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001946 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001947 int err;
1948
1949 BT_DBG("");
1950
Johan Hedberg06a63b12013-01-20 14:27:21 +02001951 memset(&rp, 0, sizeof(rp));
1952 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1953 rp.addr.type = cp->addr.type;
1954
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001955 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001956 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1957 MGMT_STATUS_INVALID_PARAMS,
1958 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001960 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001961
1962 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001963 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1964 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001965 goto failed;
1966 }
1967
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001968 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001969 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1970 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001971 goto failed;
1972 }
1973
Andre Guedes591f47f2012-04-24 21:02:49 -03001974 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001975 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1976 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001977 else
1978 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001979
Vishal Agarwalf9607272012-06-13 05:32:43 +05301980 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001981 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1982 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001983 goto failed;
1984 }
1985
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001986 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001987 if (!cmd) {
1988 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001989 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001990 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001991
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001992 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001993 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001994
1995 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1996 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001997 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001998
1999failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002000 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002001 return err;
2002}
2003
Andre Guedes57c14772012-04-24 21:02:50 -03002004static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002005{
2006 switch (link_type) {
2007 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002008 switch (addr_type) {
2009 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002010 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002011
Johan Hedberg48264f02011-11-09 13:58:58 +02002012 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002013 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002014 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002015 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002016
Johan Hedberg4c659c32011-11-07 23:13:39 +02002017 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002018 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002019 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002020 }
2021}
2022
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002023static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2024 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002025{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002026 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002027 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002028 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002029 int err;
2030 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002031
2032 BT_DBG("");
2033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002034 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002035
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002036 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002037 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002038 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002039 goto unlock;
2040 }
2041
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002042 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002043 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2044 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002045 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002046 }
2047
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002048 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002049 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002050 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002051 err = -ENOMEM;
2052 goto unlock;
2053 }
2054
Johan Hedberg2784eb42011-01-21 13:56:35 +02002055 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002056 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002057 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2058 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002059 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002060 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002061 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002062 continue;
2063 i++;
2064 }
2065
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002066 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002067
Johan Hedberg4c659c32011-11-07 23:13:39 +02002068 /* Recalculate length in case of filtered SCO connections, etc */
2069 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002070
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002071 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002072 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002073
Johan Hedberga38528f2011-01-22 06:46:43 +02002074 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002075
2076unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002077 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002078 return err;
2079}
2080
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002081static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002082 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002083{
2084 struct pending_cmd *cmd;
2085 int err;
2086
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002087 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002088 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002089 if (!cmd)
2090 return -ENOMEM;
2091
Johan Hedbergd8457692012-02-17 14:24:57 +02002092 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002094 if (err < 0)
2095 mgmt_pending_remove(cmd);
2096
2097 return err;
2098}
2099
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002100static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002101 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002102{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002103 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002104 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002105 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002106 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002107 int err;
2108
2109 BT_DBG("");
2110
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002111 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002112
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002113 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002116 goto failed;
2117 }
2118
Johan Hedbergd8457692012-02-17 14:24:57 +02002119 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002120 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002121 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002122 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002123 goto failed;
2124 }
2125
2126 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002127 struct mgmt_cp_pin_code_neg_reply ncp;
2128
2129 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002130
2131 BT_ERR("PIN code is not 16 bytes long");
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002134 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002135 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002136 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002137
2138 goto failed;
2139 }
2140
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002141 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002142 if (!cmd) {
2143 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002144 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002145 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002146
Johan Hedbergd8457692012-02-17 14:24:57 +02002147 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002148 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002149 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002150
2151 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2152 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002153 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002154
2155failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002157 return err;
2158}
2159
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002160static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2161 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002162{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002163 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002164
2165 BT_DBG("");
2166
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002167 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002168
2169 hdev->io_capability = cp->io_capability;
2170
2171 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002172 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002173
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002175
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2177 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002178}
2179
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002180static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002181{
2182 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002183 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002184
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002185 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002186 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2187 continue;
2188
Johan Hedberge9a416b2011-02-19 12:05:56 -03002189 if (cmd->user_data != conn)
2190 continue;
2191
2192 return cmd;
2193 }
2194
2195 return NULL;
2196}
2197
2198static void pairing_complete(struct pending_cmd *cmd, u8 status)
2199{
2200 struct mgmt_rp_pair_device rp;
2201 struct hci_conn *conn = cmd->user_data;
2202
Johan Hedbergba4e5642011-11-11 00:07:34 +02002203 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002204 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002205
Johan Hedbergaee9b212012-02-18 15:07:59 +02002206 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002207 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002208
2209 /* So we don't get further callbacks for this connection */
2210 conn->connect_cfm_cb = NULL;
2211 conn->security_cfm_cb = NULL;
2212 conn->disconn_cfm_cb = NULL;
2213
David Herrmann76a68ba2013-04-06 20:28:37 +02002214 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002215
Johan Hedberga664b5b2011-02-19 12:06:02 -03002216 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002217}
2218
2219static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2220{
2221 struct pending_cmd *cmd;
2222
2223 BT_DBG("status %u", status);
2224
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002225 cmd = find_pairing(conn);
2226 if (!cmd)
2227 BT_DBG("Unable to find a pending command");
2228 else
Johan Hedberge2113262012-02-18 15:20:03 +02002229 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002230}
2231
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302232static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2233{
2234 struct pending_cmd *cmd;
2235
2236 BT_DBG("status %u", status);
2237
2238 if (!status)
2239 return;
2240
2241 cmd = find_pairing(conn);
2242 if (!cmd)
2243 BT_DBG("Unable to find a pending command");
2244 else
2245 pairing_complete(cmd, mgmt_status(status));
2246}
2247
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002248static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002249 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002250{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002251 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002252 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002253 struct pending_cmd *cmd;
2254 u8 sec_level, auth_type;
2255 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002256 int err;
2257
2258 BT_DBG("");
2259
Szymon Jancf950a30e2013-01-18 12:48:07 +01002260 memset(&rp, 0, sizeof(rp));
2261 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2262 rp.addr.type = cp->addr.type;
2263
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002264 if (!bdaddr_type_is_valid(cp->addr.type))
2265 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2266 MGMT_STATUS_INVALID_PARAMS,
2267 &rp, sizeof(rp));
2268
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002270
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002271 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002272 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2273 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002274 goto unlock;
2275 }
2276
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002277 sec_level = BT_SECURITY_MEDIUM;
2278 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002279 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002280 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002281 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002282
Andre Guedes591f47f2012-04-24 21:02:49 -03002283 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002284 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2285 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002286 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002287 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2288 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002289
Ville Tervo30e76272011-02-22 16:10:53 -03002290 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002291 int status;
2292
2293 if (PTR_ERR(conn) == -EBUSY)
2294 status = MGMT_STATUS_BUSY;
2295 else
2296 status = MGMT_STATUS_CONNECT_FAILED;
2297
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002298 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002299 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002300 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002301 goto unlock;
2302 }
2303
2304 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002305 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002306 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002307 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002308 goto unlock;
2309 }
2310
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002311 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002312 if (!cmd) {
2313 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002314 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002315 goto unlock;
2316 }
2317
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002318 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002319 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002320 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302321 else
2322 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002323
Johan Hedberge9a416b2011-02-19 12:05:56 -03002324 conn->security_cfm_cb = pairing_complete_cb;
2325 conn->disconn_cfm_cb = pairing_complete_cb;
2326 conn->io_capability = cp->io_cap;
2327 cmd->user_data = conn;
2328
2329 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002330 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002331 pairing_complete(cmd, 0);
2332
2333 err = 0;
2334
2335unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002336 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002337 return err;
2338}
2339
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2341 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002342{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002343 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002344 struct pending_cmd *cmd;
2345 struct hci_conn *conn;
2346 int err;
2347
2348 BT_DBG("");
2349
Johan Hedberg28424702012-02-02 04:02:29 +02002350 hci_dev_lock(hdev);
2351
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002352 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002353 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002354 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002355 goto unlock;
2356 }
2357
Johan Hedberg28424702012-02-02 04:02:29 +02002358 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2359 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002362 goto unlock;
2363 }
2364
2365 conn = cmd->user_data;
2366
2367 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002368 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002369 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002370 goto unlock;
2371 }
2372
2373 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002375 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002376 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002377unlock:
2378 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002379 return err;
2380}
2381
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002382static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002383 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002384 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002385{
Johan Hedberga5c29682011-02-19 12:05:57 -03002386 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002387 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002388 int err;
2389
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002390 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002391
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002392 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002393 err = cmd_complete(sk, hdev->id, mgmt_op,
2394 MGMT_STATUS_NOT_POWERED, addr,
2395 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002396 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002397 }
2398
Johan Hedberg1707c602013-03-15 17:07:15 -05002399 if (addr->type == BDADDR_BREDR)
2400 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002401 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002402 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002403
Johan Hedberg272d90d2012-02-09 15:26:12 +02002404 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002405 err = cmd_complete(sk, hdev->id, mgmt_op,
2406 MGMT_STATUS_NOT_CONNECTED, addr,
2407 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002408 goto done;
2409 }
2410
Johan Hedberg1707c602013-03-15 17:07:15 -05002411 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002412 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002413 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002414
Brian Gix5fe57d92011-12-21 16:12:13 -08002415 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002416 err = cmd_complete(sk, hdev->id, mgmt_op,
2417 MGMT_STATUS_SUCCESS, addr,
2418 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002419 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002420 err = cmd_complete(sk, hdev->id, mgmt_op,
2421 MGMT_STATUS_FAILED, addr,
2422 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002423
Brian Gix47c15e22011-11-16 13:53:14 -08002424 goto done;
2425 }
2426
Johan Hedberg1707c602013-03-15 17:07:15 -05002427 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002428 if (!cmd) {
2429 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002430 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002431 }
2432
Brian Gix0df4c182011-11-16 13:53:13 -08002433 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002434 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2435 struct hci_cp_user_passkey_reply cp;
2436
Johan Hedberg1707c602013-03-15 17:07:15 -05002437 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002438 cp.passkey = passkey;
2439 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2440 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002441 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2442 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002443
Johan Hedberga664b5b2011-02-19 12:06:02 -03002444 if (err < 0)
2445 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002446
Brian Gix0df4c182011-11-16 13:53:13 -08002447done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002448 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002449 return err;
2450}
2451
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302452static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2453 void *data, u16 len)
2454{
2455 struct mgmt_cp_pin_code_neg_reply *cp = data;
2456
2457 BT_DBG("");
2458
Johan Hedberg1707c602013-03-15 17:07:15 -05002459 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302460 MGMT_OP_PIN_CODE_NEG_REPLY,
2461 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2462}
2463
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002464static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2465 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002466{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002467 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002468
2469 BT_DBG("");
2470
2471 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002472 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002474
Johan Hedberg1707c602013-03-15 17:07:15 -05002475 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002476 MGMT_OP_USER_CONFIRM_REPLY,
2477 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002478}
2479
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002480static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002481 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002482{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002483 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002484
2485 BT_DBG("");
2486
Johan Hedberg1707c602013-03-15 17:07:15 -05002487 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002488 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2489 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002490}
2491
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002492static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2493 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002494{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002495 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002496
2497 BT_DBG("");
2498
Johan Hedberg1707c602013-03-15 17:07:15 -05002499 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002500 MGMT_OP_USER_PASSKEY_REPLY,
2501 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002502}
2503
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002504static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002505 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002506{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002508
2509 BT_DBG("");
2510
Johan Hedberg1707c602013-03-15 17:07:15 -05002511 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002512 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2513 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002514}
2515
Johan Hedberg13928972013-03-15 17:07:00 -05002516static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002517{
Johan Hedberg13928972013-03-15 17:07:00 -05002518 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002519 struct hci_cp_write_local_name cp;
2520
Johan Hedberg13928972013-03-15 17:07:00 -05002521 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002522
Johan Hedberg890ea892013-03-15 17:06:52 -05002523 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002524}
2525
Johan Hedberg13928972013-03-15 17:07:00 -05002526static void set_name_complete(struct hci_dev *hdev, u8 status)
2527{
2528 struct mgmt_cp_set_local_name *cp;
2529 struct pending_cmd *cmd;
2530
2531 BT_DBG("status 0x%02x", status);
2532
2533 hci_dev_lock(hdev);
2534
2535 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2536 if (!cmd)
2537 goto unlock;
2538
2539 cp = cmd->param;
2540
2541 if (status)
2542 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2543 mgmt_status(status));
2544 else
2545 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2546 cp, sizeof(*cp));
2547
2548 mgmt_pending_remove(cmd);
2549
2550unlock:
2551 hci_dev_unlock(hdev);
2552}
2553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002554static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002556{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002557 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002558 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002559 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002560 int err;
2561
2562 BT_DBG("");
2563
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002564 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002565
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002566 /* If the old values are the same as the new ones just return a
2567 * direct command complete event.
2568 */
2569 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2570 !memcmp(hdev->short_name, cp->short_name,
2571 sizeof(hdev->short_name))) {
2572 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2573 data, len);
2574 goto failed;
2575 }
2576
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002577 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002578
Johan Hedbergb5235a62012-02-21 14:32:24 +02002579 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002580 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002581
2582 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002583 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002584 if (err < 0)
2585 goto failed;
2586
2587 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002589
Johan Hedbergb5235a62012-02-21 14:32:24 +02002590 goto failed;
2591 }
2592
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002593 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002594 if (!cmd) {
2595 err = -ENOMEM;
2596 goto failed;
2597 }
2598
Johan Hedberg13928972013-03-15 17:07:00 -05002599 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2600
Johan Hedberg890ea892013-03-15 17:06:52 -05002601 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002602
2603 if (lmp_bredr_capable(hdev)) {
2604 update_name(&req);
2605 update_eir(&req);
2606 }
2607
2608 if (lmp_le_capable(hdev))
2609 hci_update_ad(&req);
2610
Johan Hedberg13928972013-03-15 17:07:00 -05002611 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002612 if (err < 0)
2613 mgmt_pending_remove(cmd);
2614
2615failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002616 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002617 return err;
2618}
2619
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002620static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002621 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002622{
Szymon Jancc35938b2011-03-22 13:12:21 +01002623 struct pending_cmd *cmd;
2624 int err;
2625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002627
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002628 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002629
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002630 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002631 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002632 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002633 goto unlock;
2634 }
2635
Andre Guedes9a1a1992012-07-24 15:03:48 -03002636 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002639 goto unlock;
2640 }
2641
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002642 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002643 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002644 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002645 goto unlock;
2646 }
2647
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002648 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002649 if (!cmd) {
2650 err = -ENOMEM;
2651 goto unlock;
2652 }
2653
2654 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2655 if (err < 0)
2656 mgmt_pending_remove(cmd);
2657
2658unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002659 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002660 return err;
2661}
2662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002663static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002664 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002665{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002666 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002667 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002668 int err;
2669
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002670 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002671
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002672 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002673
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002674 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002675 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002676 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002677 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002678 else
Szymon Janca6785be2012-12-13 15:11:21 +01002679 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002680
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002681 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002682 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002683
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002684 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002685 return err;
2686}
2687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002688static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002689 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002690{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002691 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002692 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002693 int err;
2694
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002695 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002696
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002697 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002698
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002699 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002700 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002701 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002702 else
Szymon Janca6785be2012-12-13 15:11:21 +01002703 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002705 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002706 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002707
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002708 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002709 return err;
2710}
2711
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002712static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2713{
2714 struct pending_cmd *cmd;
2715 u8 type;
2716 int err;
2717
2718 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2719
2720 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2721 if (!cmd)
2722 return -ENOENT;
2723
2724 type = hdev->discovery.type;
2725
2726 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2727 &type, sizeof(type));
2728 mgmt_pending_remove(cmd);
2729
2730 return err;
2731}
2732
Andre Guedes7c307722013-04-30 15:29:28 -03002733static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2734{
2735 BT_DBG("status %d", status);
2736
2737 if (status) {
2738 hci_dev_lock(hdev);
2739 mgmt_start_discovery_failed(hdev, status);
2740 hci_dev_unlock(hdev);
2741 return;
2742 }
2743
2744 hci_dev_lock(hdev);
2745 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2746 hci_dev_unlock(hdev);
2747
2748 switch (hdev->discovery.type) {
2749 case DISCOV_TYPE_LE:
2750 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002751 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002752 break;
2753
2754 case DISCOV_TYPE_INTERLEAVED:
2755 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002756 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002757 break;
2758
2759 case DISCOV_TYPE_BREDR:
2760 break;
2761
2762 default:
2763 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2764 }
2765}
2766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002767static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002768 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002769{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002770 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002771 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002772 struct hci_cp_le_set_scan_param param_cp;
2773 struct hci_cp_le_set_scan_enable enable_cp;
2774 struct hci_cp_inquiry inq_cp;
2775 struct hci_request req;
2776 /* General inquiry access code (GIAC) */
2777 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002778 int err;
2779
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002780 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002781
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002782 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002783
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002784 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002785 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002786 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002787 goto failed;
2788 }
2789
Andre Guedes642be6c2012-03-21 00:03:37 -03002790 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2791 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2792 MGMT_STATUS_BUSY);
2793 goto failed;
2794 }
2795
Johan Hedbergff9ef572012-01-04 14:23:45 +02002796 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002797 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002798 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002799 goto failed;
2800 }
2801
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002802 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002803 if (!cmd) {
2804 err = -ENOMEM;
2805 goto failed;
2806 }
2807
Andre Guedes4aab14e2012-02-17 20:39:36 -03002808 hdev->discovery.type = cp->type;
2809
Andre Guedes7c307722013-04-30 15:29:28 -03002810 hci_req_init(&req, hdev);
2811
Andre Guedes4aab14e2012-02-17 20:39:36 -03002812 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002813 case DISCOV_TYPE_BREDR:
Johan Hedberg56f87902013-10-02 13:43:13 +03002814 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002815 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2816 MGMT_STATUS_NOT_SUPPORTED);
2817 mgmt_pending_remove(cmd);
2818 goto failed;
2819 }
2820
Andre Guedes7c307722013-04-30 15:29:28 -03002821 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2822 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2823 MGMT_STATUS_BUSY);
2824 mgmt_pending_remove(cmd);
2825 goto failed;
2826 }
2827
2828 hci_inquiry_cache_flush(hdev);
2829
2830 memset(&inq_cp, 0, sizeof(inq_cp));
2831 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002832 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002833 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002834 break;
2835
2836 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002837 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002838 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002839 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2840 MGMT_STATUS_NOT_SUPPORTED);
2841 mgmt_pending_remove(cmd);
2842 goto failed;
2843 }
2844
Andre Guedes7c307722013-04-30 15:29:28 -03002845 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002846 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002847 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2848 MGMT_STATUS_NOT_SUPPORTED);
2849 mgmt_pending_remove(cmd);
2850 goto failed;
2851 }
2852
Andre Guedes7c307722013-04-30 15:29:28 -03002853 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2854 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2855 MGMT_STATUS_REJECTED);
2856 mgmt_pending_remove(cmd);
2857 goto failed;
2858 }
2859
2860 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2861 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2862 MGMT_STATUS_BUSY);
2863 mgmt_pending_remove(cmd);
2864 goto failed;
2865 }
2866
2867 memset(&param_cp, 0, sizeof(param_cp));
2868 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002869 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2870 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002871 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2872 &param_cp);
2873
2874 memset(&enable_cp, 0, sizeof(enable_cp));
2875 enable_cp.enable = LE_SCAN_ENABLE;
2876 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2877 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2878 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002879 break;
2880
Andre Guedesf39799f2012-02-17 20:39:35 -03002881 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002882 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2883 MGMT_STATUS_INVALID_PARAMS);
2884 mgmt_pending_remove(cmd);
2885 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002886 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002887
Andre Guedes7c307722013-04-30 15:29:28 -03002888 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002889 if (err < 0)
2890 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002891 else
2892 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002893
2894failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002895 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002896 return err;
2897}
2898
Andre Guedes1183fdc2013-04-30 15:29:35 -03002899static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2900{
2901 struct pending_cmd *cmd;
2902 int err;
2903
2904 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2905 if (!cmd)
2906 return -ENOENT;
2907
2908 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2909 &hdev->discovery.type, sizeof(hdev->discovery.type));
2910 mgmt_pending_remove(cmd);
2911
2912 return err;
2913}
2914
Andre Guedes0e05bba2013-04-30 15:29:33 -03002915static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2916{
2917 BT_DBG("status %d", status);
2918
2919 hci_dev_lock(hdev);
2920
2921 if (status) {
2922 mgmt_stop_discovery_failed(hdev, status);
2923 goto unlock;
2924 }
2925
2926 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2927
2928unlock:
2929 hci_dev_unlock(hdev);
2930}
2931
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002932static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002933 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002934{
Johan Hedbergd9306502012-02-20 23:25:18 +02002935 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002936 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002937 struct hci_cp_remote_name_req_cancel cp;
2938 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002939 struct hci_request req;
2940 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002941 int err;
2942
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002943 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002944
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002945 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002946
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002947 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002948 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002949 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2950 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002951 goto unlock;
2952 }
2953
2954 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002955 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002956 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2957 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002958 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002959 }
2960
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002961 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002962 if (!cmd) {
2963 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002964 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002965 }
2966
Andre Guedes0e05bba2013-04-30 15:29:33 -03002967 hci_req_init(&req, hdev);
2968
Andre Guedese0d9727e2012-03-20 15:15:36 -03002969 switch (hdev->discovery.state) {
2970 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002971 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2972 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2973 } else {
2974 cancel_delayed_work(&hdev->le_scan_disable);
2975
2976 memset(&enable_cp, 0, sizeof(enable_cp));
2977 enable_cp.enable = LE_SCAN_DISABLE;
2978 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2979 sizeof(enable_cp), &enable_cp);
2980 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002981
Andre Guedese0d9727e2012-03-20 15:15:36 -03002982 break;
2983
2984 case DISCOVERY_RESOLVING:
2985 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002986 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002987 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002988 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002989 err = cmd_complete(sk, hdev->id,
2990 MGMT_OP_STOP_DISCOVERY, 0,
2991 &mgmt_cp->type,
2992 sizeof(mgmt_cp->type));
2993 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2994 goto unlock;
2995 }
2996
2997 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002998 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2999 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003000
3001 break;
3002
3003 default:
3004 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003005
3006 mgmt_pending_remove(cmd);
3007 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3008 MGMT_STATUS_FAILED, &mgmt_cp->type,
3009 sizeof(mgmt_cp->type));
3010 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003011 }
3012
Andre Guedes0e05bba2013-04-30 15:29:33 -03003013 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003014 if (err < 0)
3015 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003016 else
3017 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003018
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003019unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003020 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003021 return err;
3022}
3023
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003024static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003025 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003026{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003027 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003028 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003029 int err;
3030
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003031 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003032
Johan Hedberg561aafb2012-01-04 13:31:59 +02003033 hci_dev_lock(hdev);
3034
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003035 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003036 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003037 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003038 goto failed;
3039 }
3040
Johan Hedberga198e7b2012-02-17 14:27:06 +02003041 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003042 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003043 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003044 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003045 goto failed;
3046 }
3047
3048 if (cp->name_known) {
3049 e->name_state = NAME_KNOWN;
3050 list_del(&e->list);
3051 } else {
3052 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003053 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003054 }
3055
Johan Hedberge3846622013-01-09 15:29:33 +02003056 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3057 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003058
3059failed:
3060 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003061 return err;
3062}
3063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003064static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003065 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003066{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003067 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003068 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003069 int err;
3070
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003071 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003072
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003073 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003074 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3075 MGMT_STATUS_INVALID_PARAMS,
3076 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003077
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003078 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003079
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003080 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003081 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003082 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003083 else
Szymon Janca6785be2012-12-13 15:11:21 +01003084 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003086 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003089 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003090
3091 return err;
3092}
3093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003094static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003095 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003096{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003097 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003098 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003099 int err;
3100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003101 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003102
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003103 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003104 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3105 MGMT_STATUS_INVALID_PARAMS,
3106 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003107
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003108 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003109
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003110 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003111 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003112 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003113 else
Szymon Janca6785be2012-12-13 15:11:21 +01003114 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003116 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003117 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003118
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003119 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003120
3121 return err;
3122}
3123
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003124static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3125 u16 len)
3126{
3127 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003128 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003129 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003130 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003131
3132 BT_DBG("%s", hdev->name);
3133
Szymon Jancc72d4b82012-03-16 16:02:57 +01003134 source = __le16_to_cpu(cp->source);
3135
3136 if (source > 0x0002)
3137 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3138 MGMT_STATUS_INVALID_PARAMS);
3139
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003140 hci_dev_lock(hdev);
3141
Szymon Jancc72d4b82012-03-16 16:02:57 +01003142 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003143 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3144 hdev->devid_product = __le16_to_cpu(cp->product);
3145 hdev->devid_version = __le16_to_cpu(cp->version);
3146
3147 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3148
Johan Hedberg890ea892013-03-15 17:06:52 -05003149 hci_req_init(&req, hdev);
3150 update_eir(&req);
3151 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003152
3153 hci_dev_unlock(hdev);
3154
3155 return err;
3156}
3157
Johan Hedberg4375f102013-09-25 13:26:10 +03003158static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3159{
3160 struct cmd_lookup match = { NULL, hdev };
3161
3162 if (status) {
3163 u8 mgmt_err = mgmt_status(status);
3164
3165 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3166 cmd_status_rsp, &mgmt_err);
3167 return;
3168 }
3169
3170 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3171 &match);
3172
3173 new_settings(hdev, match.sk);
3174
3175 if (match.sk)
3176 sock_put(match.sk);
3177}
3178
3179static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3180{
3181 struct mgmt_mode *cp = data;
3182 struct pending_cmd *cmd;
3183 struct hci_request req;
3184 u8 val, enabled;
3185 int err;
3186
3187 BT_DBG("request for %s", hdev->name);
3188
3189 if (!lmp_le_capable(hdev))
3190 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3191 MGMT_STATUS_NOT_SUPPORTED);
3192
3193 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3194 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3195 MGMT_STATUS_REJECTED);
3196
3197 if (cp->val != 0x00 && cp->val != 0x01)
3198 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3199 MGMT_STATUS_INVALID_PARAMS);
3200
3201 hci_dev_lock(hdev);
3202
3203 val = !!cp->val;
3204 enabled = test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3205
3206 if (!hdev_is_powered(hdev) || val == enabled) {
3207 bool changed = false;
3208
3209 if (val != test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3210 change_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
3211 changed = true;
3212 }
3213
3214 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3215 if (err < 0)
3216 goto unlock;
3217
3218 if (changed)
3219 err = new_settings(hdev, sk);
3220
3221 goto unlock;
3222 }
3223
3224 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3225 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3226 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3227 MGMT_STATUS_BUSY);
3228 goto unlock;
3229 }
3230
3231 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3232 if (!cmd) {
3233 err = -ENOMEM;
3234 goto unlock;
3235 }
3236
3237 hci_req_init(&req, hdev);
3238
3239 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
3240
3241 err = hci_req_run(&req, set_advertising_complete);
3242 if (err < 0)
3243 mgmt_pending_remove(cmd);
3244
3245unlock:
3246 hci_dev_unlock(hdev);
3247 return err;
3248}
3249
Johan Hedberg33e38b32013-03-15 17:07:05 -05003250static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3251{
3252 struct pending_cmd *cmd;
3253
3254 BT_DBG("status 0x%02x", status);
3255
3256 hci_dev_lock(hdev);
3257
3258 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3259 if (!cmd)
3260 goto unlock;
3261
3262 if (status) {
3263 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3264 mgmt_status(status));
3265 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003266 struct mgmt_mode *cp = cmd->param;
3267
3268 if (cp->val)
3269 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3270 else
3271 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3272
Johan Hedberg33e38b32013-03-15 17:07:05 -05003273 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3274 new_settings(hdev, cmd->sk);
3275 }
3276
3277 mgmt_pending_remove(cmd);
3278
3279unlock:
3280 hci_dev_unlock(hdev);
3281}
3282
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003283static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003284 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003285{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003286 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003287 struct pending_cmd *cmd;
3288 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003289 int err;
3290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003291 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003292
Johan Hedberg56f87902013-10-02 13:43:13 +03003293 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3294 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003295 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3296 MGMT_STATUS_NOT_SUPPORTED);
3297
Johan Hedberga7e80f22013-01-09 16:05:19 +02003298 if (cp->val != 0x00 && cp->val != 0x01)
3299 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3300 MGMT_STATUS_INVALID_PARAMS);
3301
Johan Hedberg5400c042012-02-21 16:40:33 +02003302 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003303 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003304 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003305
3306 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003307 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003308 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003309
3310 hci_dev_lock(hdev);
3311
Johan Hedberg05cbf292013-03-15 17:07:07 -05003312 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3313 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3314 MGMT_STATUS_BUSY);
3315 goto unlock;
3316 }
3317
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003318 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3319 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3320 hdev);
3321 goto unlock;
3322 }
3323
Johan Hedberg33e38b32013-03-15 17:07:05 -05003324 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3325 data, len);
3326 if (!cmd) {
3327 err = -ENOMEM;
3328 goto unlock;
3329 }
3330
3331 hci_req_init(&req, hdev);
3332
Johan Hedberg406d7802013-03-15 17:07:09 -05003333 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003334
3335 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003336 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003337 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003338 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003339 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003340 }
3341
Johan Hedberg33e38b32013-03-15 17:07:05 -05003342unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003343 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003344
Antti Julkuf6422ec2011-06-22 13:11:56 +03003345 return err;
3346}
3347
Johan Hedberg0663ca22013-10-02 13:43:14 +03003348static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3349{
3350 struct pending_cmd *cmd;
3351
3352 BT_DBG("status 0x%02x", status);
3353
3354 hci_dev_lock(hdev);
3355
3356 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3357 if (!cmd)
3358 goto unlock;
3359
3360 if (status) {
3361 u8 mgmt_err = mgmt_status(status);
3362
3363 /* We need to restore the flag if related HCI commands
3364 * failed.
3365 */
3366 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3367
3368 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3369 } else {
3370 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3371 new_settings(hdev, cmd->sk);
3372 }
3373
3374 mgmt_pending_remove(cmd);
3375
3376unlock:
3377 hci_dev_unlock(hdev);
3378}
3379
3380static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3381{
3382 struct mgmt_mode *cp = data;
3383 struct pending_cmd *cmd;
3384 struct hci_request req;
3385 int err;
3386
3387 BT_DBG("request for %s", hdev->name);
3388
3389 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3390 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3391 MGMT_STATUS_NOT_SUPPORTED);
3392
3393 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3394 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3395 MGMT_STATUS_REJECTED);
3396
3397 if (cp->val != 0x00 && cp->val != 0x01)
3398 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3399 MGMT_STATUS_INVALID_PARAMS);
3400
3401 hci_dev_lock(hdev);
3402
3403 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3404 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3405 goto unlock;
3406 }
3407
3408 if (!hdev_is_powered(hdev)) {
3409 if (!cp->val) {
3410 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3411 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3412 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3413 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3414 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3415 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3416 }
3417
3418 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3419
3420 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3421 if (err < 0)
3422 goto unlock;
3423
3424 err = new_settings(hdev, sk);
3425 goto unlock;
3426 }
3427
3428 /* Reject disabling when powered on */
3429 if (!cp->val) {
3430 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3431 MGMT_STATUS_REJECTED);
3432 goto unlock;
3433 }
3434
3435 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3436 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3437 MGMT_STATUS_BUSY);
3438 goto unlock;
3439 }
3440
3441 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3442 if (!cmd) {
3443 err = -ENOMEM;
3444 goto unlock;
3445 }
3446
3447 /* We need to flip the bit already here so that hci_update_ad
3448 * generates the correct flags.
3449 */
3450 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3451
3452 hci_req_init(&req, hdev);
3453 hci_update_ad(&req);
3454 err = hci_req_run(&req, set_bredr_complete);
3455 if (err < 0)
3456 mgmt_pending_remove(cmd);
3457
3458unlock:
3459 hci_dev_unlock(hdev);
3460 return err;
3461}
3462
Johan Hedberg3f706b72013-01-20 14:27:16 +02003463static bool ltk_is_valid(struct mgmt_ltk_info *key)
3464{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003465 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3466 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003467 if (key->master != 0x00 && key->master != 0x01)
3468 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003469 if (!bdaddr_type_is_le(key->addr.type))
3470 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003471 return true;
3472}
3473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003474static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003475 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003476{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003477 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3478 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003479 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003480
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003481 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003482
3483 expected_len = sizeof(*cp) + key_count *
3484 sizeof(struct mgmt_ltk_info);
3485 if (expected_len != len) {
3486 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003487 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003488 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003489 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003490 }
3491
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003492 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003493
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003494 for (i = 0; i < key_count; i++) {
3495 struct mgmt_ltk_info *key = &cp->keys[i];
3496
Johan Hedberg3f706b72013-01-20 14:27:16 +02003497 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003498 return cmd_status(sk, hdev->id,
3499 MGMT_OP_LOAD_LONG_TERM_KEYS,
3500 MGMT_STATUS_INVALID_PARAMS);
3501 }
3502
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003503 hci_dev_lock(hdev);
3504
3505 hci_smp_ltks_clear(hdev);
3506
3507 for (i = 0; i < key_count; i++) {
3508 struct mgmt_ltk_info *key = &cp->keys[i];
3509 u8 type;
3510
3511 if (key->master)
3512 type = HCI_SMP_LTK;
3513 else
3514 type = HCI_SMP_LTK_SLAVE;
3515
Hemant Gupta4596fde2012-04-16 14:57:40 +05303516 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003517 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003518 type, 0, key->authenticated, key->val,
3519 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003520 }
3521
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003522 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3523 NULL, 0);
3524
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003525 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003526
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003527 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003528}
3529
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003530static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003531 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3532 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003533 bool var_len;
3534 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003535} mgmt_handlers[] = {
3536 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003537 { read_version, false, MGMT_READ_VERSION_SIZE },
3538 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3539 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3540 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3541 { set_powered, false, MGMT_SETTING_SIZE },
3542 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3543 { set_connectable, false, MGMT_SETTING_SIZE },
3544 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3545 { set_pairable, false, MGMT_SETTING_SIZE },
3546 { set_link_security, false, MGMT_SETTING_SIZE },
3547 { set_ssp, false, MGMT_SETTING_SIZE },
3548 { set_hs, false, MGMT_SETTING_SIZE },
3549 { set_le, false, MGMT_SETTING_SIZE },
3550 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3551 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3552 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3553 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3554 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3555 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3556 { disconnect, false, MGMT_DISCONNECT_SIZE },
3557 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3558 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3559 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3560 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3561 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3562 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3563 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3564 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3565 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3566 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3567 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3568 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3569 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3570 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3571 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3572 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3573 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3574 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3575 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003576 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003577 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003578 { set_bredr, false, MGMT_SETTING_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003579};
3580
3581
Johan Hedberg03811012010-12-08 00:21:06 +02003582int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3583{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003584 void *buf;
3585 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003586 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003587 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003588 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003589 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003590 int err;
3591
3592 BT_DBG("got %zu bytes", msglen);
3593
3594 if (msglen < sizeof(*hdr))
3595 return -EINVAL;
3596
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003597 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003598 if (!buf)
3599 return -ENOMEM;
3600
3601 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3602 err = -EFAULT;
3603 goto done;
3604 }
3605
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003606 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003607 opcode = __le16_to_cpu(hdr->opcode);
3608 index = __le16_to_cpu(hdr->index);
3609 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003610
3611 if (len != msglen - sizeof(*hdr)) {
3612 err = -EINVAL;
3613 goto done;
3614 }
3615
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003616 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003617 hdev = hci_dev_get(index);
3618 if (!hdev) {
3619 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003620 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003621 goto done;
3622 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003623
3624 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3625 err = cmd_status(sk, index, opcode,
3626 MGMT_STATUS_INVALID_INDEX);
3627 goto done;
3628 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003629 }
3630
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003631 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003632 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003633 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003634 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003635 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003636 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003637 }
3638
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003639 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003640 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003641 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003642 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003643 goto done;
3644 }
3645
Johan Hedbergbe22b542012-03-01 22:24:41 +02003646 handler = &mgmt_handlers[opcode];
3647
3648 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003649 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003650 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003651 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003652 goto done;
3653 }
3654
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003655 if (hdev)
3656 mgmt_init_hdev(sk, hdev);
3657
3658 cp = buf + sizeof(*hdr);
3659
Johan Hedbergbe22b542012-03-01 22:24:41 +02003660 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003661 if (err < 0)
3662 goto done;
3663
Johan Hedberg03811012010-12-08 00:21:06 +02003664 err = msglen;
3665
3666done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003667 if (hdev)
3668 hci_dev_put(hdev);
3669
Johan Hedberg03811012010-12-08 00:21:06 +02003670 kfree(buf);
3671 return err;
3672}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003673
Johan Hedberg744cf192011-11-08 20:40:14 +02003674int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003675{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003676 if (!mgmt_valid_hdev(hdev))
3677 return -ENOTSUPP;
3678
Johan Hedberg744cf192011-11-08 20:40:14 +02003679 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003680}
3681
Johan Hedberg744cf192011-11-08 20:40:14 +02003682int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003683{
Johan Hedberg5f159032012-03-02 03:13:19 +02003684 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003685
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003686 if (!mgmt_valid_hdev(hdev))
3687 return -ENOTSUPP;
3688
Johan Hedberg744cf192011-11-08 20:40:14 +02003689 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003690
Johan Hedberg744cf192011-11-08 20:40:14 +02003691 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003692}
3693
Johan Hedberg890ea892013-03-15 17:06:52 -05003694static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003695{
Johan Hedberg890ea892013-03-15 17:06:52 -05003696 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003697 u8 scan = 0;
3698
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003699 /* Ensure that fast connectable is disabled. This function will
3700 * not do anything if the page scan parameters are already what
3701 * they should be.
3702 */
3703 write_fast_connectable(req, false);
3704
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003705 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3706 scan |= SCAN_PAGE;
3707 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3708 scan |= SCAN_INQUIRY;
3709
Johan Hedberg890ea892013-03-15 17:06:52 -05003710 if (scan)
3711 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003712}
3713
Johan Hedberg229ab392013-03-15 17:06:53 -05003714static void powered_complete(struct hci_dev *hdev, u8 status)
3715{
3716 struct cmd_lookup match = { NULL, hdev };
3717
3718 BT_DBG("status 0x%02x", status);
3719
3720 hci_dev_lock(hdev);
3721
3722 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3723
3724 new_settings(hdev, match.sk);
3725
3726 hci_dev_unlock(hdev);
3727
3728 if (match.sk)
3729 sock_put(match.sk);
3730}
3731
Johan Hedberg70da6242013-03-15 17:06:51 -05003732static int powered_update_hci(struct hci_dev *hdev)
3733{
Johan Hedberg890ea892013-03-15 17:06:52 -05003734 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003735 u8 link_sec;
3736
Johan Hedberg890ea892013-03-15 17:06:52 -05003737 hci_req_init(&req, hdev);
3738
Johan Hedberg70da6242013-03-15 17:06:51 -05003739 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3740 !lmp_host_ssp_capable(hdev)) {
3741 u8 ssp = 1;
3742
Johan Hedberg890ea892013-03-15 17:06:52 -05003743 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003744 }
3745
Johan Hedbergc73eee92013-04-19 18:35:21 +03003746 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3747 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003748 struct hci_cp_write_le_host_supported cp;
3749
3750 cp.le = 1;
3751 cp.simul = lmp_le_br_capable(hdev);
3752
3753 /* Check first if we already have the right
3754 * host state (host features set)
3755 */
3756 if (cp.le != lmp_host_le_capable(hdev) ||
3757 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003758 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3759 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003760
3761 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3762 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003763 }
3764
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003765 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3766 u8 adv = 0x01;
3767
3768 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3769 }
3770
Johan Hedberg70da6242013-03-15 17:06:51 -05003771 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3772 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003773 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3774 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003775
3776 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003777 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3778 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003779 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003780 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003781 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003782 }
3783
Johan Hedberg229ab392013-03-15 17:06:53 -05003784 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003785}
3786
Johan Hedberg744cf192011-11-08 20:40:14 +02003787int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003788{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003789 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003790 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3791 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003792 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003793
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003794 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3795 return 0;
3796
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003797 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003798 if (powered_update_hci(hdev) == 0)
3799 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003800
Johan Hedberg229ab392013-03-15 17:06:53 -05003801 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3802 &match);
3803 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003804 }
3805
Johan Hedberg229ab392013-03-15 17:06:53 -05003806 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3807 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3808
3809 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3810 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3811 zero_cod, sizeof(zero_cod), NULL);
3812
3813new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003814 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003815
3816 if (match.sk)
3817 sock_put(match.sk);
3818
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003819 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003820}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003821
Johan Hedberg96570ff2013-05-29 09:51:29 +03003822int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3823{
3824 struct pending_cmd *cmd;
3825 u8 status;
3826
3827 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3828 if (!cmd)
3829 return -ENOENT;
3830
3831 if (err == -ERFKILL)
3832 status = MGMT_STATUS_RFKILLED;
3833 else
3834 status = MGMT_STATUS_FAILED;
3835
3836 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3837
3838 mgmt_pending_remove(cmd);
3839
3840 return err;
3841}
3842
Johan Hedberg744cf192011-11-08 20:40:14 +02003843int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003844{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003845 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003846 bool changed = false;
3847 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003848
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003849 if (discoverable) {
3850 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3851 changed = true;
3852 } else {
3853 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3854 changed = true;
3855 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003856
Johan Hedberged9b5f22012-02-21 20:47:06 +02003857 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003858 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003859
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003860 if (changed)
3861 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003862
Johan Hedberg73f22f62010-12-29 16:00:25 +02003863 if (match.sk)
3864 sock_put(match.sk);
3865
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003866 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003867}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003868
Johan Hedberg744cf192011-11-08 20:40:14 +02003869int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003870{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003871 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003872 bool changed = false;
3873 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003874
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003875 if (connectable) {
3876 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3877 changed = true;
3878 } else {
3879 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3880 changed = true;
3881 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003882
Johan Hedberg2b76f452013-03-15 17:07:04 -05003883 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003884
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003885 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003886 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003887
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003888 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003889}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003890
Johan Hedberg744cf192011-11-08 20:40:14 +02003891int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003892{
Johan Hedbergca69b792011-11-11 18:10:00 +02003893 u8 mgmt_err = mgmt_status(status);
3894
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003895 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003896 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003897 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003898
3899 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003900 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003901 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003902
3903 return 0;
3904}
3905
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003906int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3907 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003908{
Johan Hedberg86742e12011-11-07 23:13:38 +02003909 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003910
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003911 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003912
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003913 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003914 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003915 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003916 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003917 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003918 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003919
Johan Hedberg744cf192011-11-08 20:40:14 +02003920 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003921}
Johan Hedbergf7520542011-01-20 12:34:39 +02003922
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003923int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3924{
3925 struct mgmt_ev_new_long_term_key ev;
3926
3927 memset(&ev, 0, sizeof(ev));
3928
3929 ev.store_hint = persistent;
3930 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003931 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003932 ev.key.authenticated = key->authenticated;
3933 ev.key.enc_size = key->enc_size;
3934 ev.key.ediv = key->ediv;
3935
3936 if (key->type == HCI_SMP_LTK)
3937 ev.key.master = 1;
3938
3939 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3940 memcpy(ev.key.val, key->val, sizeof(key->val));
3941
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003942 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3943 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003944}
3945
Johan Hedbergafc747a2012-01-15 18:11:07 +02003946int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003947 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3948 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003949{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003950 char buf[512];
3951 struct mgmt_ev_device_connected *ev = (void *) buf;
3952 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003953
Johan Hedbergb644ba32012-01-17 21:48:47 +02003954 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003955 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003956
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003957 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003958
Johan Hedbergb644ba32012-01-17 21:48:47 +02003959 if (name_len > 0)
3960 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003961 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003962
3963 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003964 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003965 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003966
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003967 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003968
3969 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003970 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003971}
3972
Johan Hedberg8962ee72011-01-20 12:40:27 +02003973static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3974{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003975 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003976 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003977 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003978
Johan Hedberg88c3df12012-02-09 14:27:38 +02003979 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3980 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003981
Johan Hedbergaee9b212012-02-18 15:07:59 +02003982 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003983 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003984
3985 *sk = cmd->sk;
3986 sock_hold(*sk);
3987
Johan Hedberga664b5b2011-02-19 12:06:02 -03003988 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003989}
3990
Johan Hedberg124f6e32012-02-09 13:50:12 +02003991static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003992{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003993 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003994 struct mgmt_cp_unpair_device *cp = cmd->param;
3995 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003996
3997 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003998 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3999 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004000
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004001 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4002
Johan Hedbergaee9b212012-02-18 15:07:59 +02004003 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004004
4005 mgmt_pending_remove(cmd);
4006}
4007
Johan Hedbergafc747a2012-01-15 18:11:07 +02004008int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004009 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004010{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004011 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004012 struct sock *sk = NULL;
4013 int err;
4014
Johan Hedberg744cf192011-11-08 20:40:14 +02004015 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004016
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004017 bacpy(&ev.addr.bdaddr, bdaddr);
4018 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4019 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004020
Johan Hedbergafc747a2012-01-15 18:11:07 +02004021 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004022 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004023
4024 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004025 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004026
Johan Hedberg124f6e32012-02-09 13:50:12 +02004027 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004028 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02004029
Johan Hedberg8962ee72011-01-20 12:40:27 +02004030 return err;
4031}
4032
Johan Hedberg88c3df12012-02-09 14:27:38 +02004033int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004034 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004035{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004036 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004037 struct pending_cmd *cmd;
4038 int err;
4039
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004040 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4041 hdev);
4042
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004043 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004044 if (!cmd)
4045 return -ENOENT;
4046
Johan Hedberg88c3df12012-02-09 14:27:38 +02004047 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004048 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004049
Johan Hedberg88c3df12012-02-09 14:27:38 +02004050 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004051 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004052
Johan Hedberga664b5b2011-02-19 12:06:02 -03004053 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004054
4055 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02004056}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004057
Johan Hedberg48264f02011-11-09 13:58:58 +02004058int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004059 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004060{
4061 struct mgmt_ev_connect_failed ev;
4062
Johan Hedberg4c659c32011-11-07 23:13:39 +02004063 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004064 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004065 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004066
Johan Hedberg744cf192011-11-08 20:40:14 +02004067 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004068}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004069
Johan Hedberg744cf192011-11-08 20:40:14 +02004070int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004071{
4072 struct mgmt_ev_pin_code_request ev;
4073
Johan Hedbergd8457692012-02-17 14:24:57 +02004074 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004075 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004076 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004077
Johan Hedberg744cf192011-11-08 20:40:14 +02004078 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004079 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004080}
4081
Johan Hedberg744cf192011-11-08 20:40:14 +02004082int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004083 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004084{
4085 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004086 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004087 int err;
4088
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004089 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004090 if (!cmd)
4091 return -ENOENT;
4092
Johan Hedbergd8457692012-02-17 14:24:57 +02004093 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004094 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004095
Johan Hedbergaee9b212012-02-18 15:07:59 +02004096 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004097 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004098
Johan Hedberga664b5b2011-02-19 12:06:02 -03004099 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004100
4101 return err;
4102}
4103
Johan Hedberg744cf192011-11-08 20:40:14 +02004104int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004105 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004106{
4107 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004108 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004109 int err;
4110
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004111 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004112 if (!cmd)
4113 return -ENOENT;
4114
Johan Hedbergd8457692012-02-17 14:24:57 +02004115 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004116 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004117
Johan Hedbergaee9b212012-02-18 15:07:59 +02004118 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004119 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004120
Johan Hedberga664b5b2011-02-19 12:06:02 -03004121 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004122
4123 return err;
4124}
Johan Hedberga5c29682011-02-19 12:05:57 -03004125
Johan Hedberg744cf192011-11-08 20:40:14 +02004126int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004127 u8 link_type, u8 addr_type, __le32 value,
4128 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004129{
4130 struct mgmt_ev_user_confirm_request ev;
4131
Johan Hedberg744cf192011-11-08 20:40:14 +02004132 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004133
Johan Hedberg272d90d2012-02-09 15:26:12 +02004134 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004135 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004136 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004137 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004138
Johan Hedberg744cf192011-11-08 20:40:14 +02004139 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004140 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004141}
4142
Johan Hedberg272d90d2012-02-09 15:26:12 +02004143int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004144 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004145{
4146 struct mgmt_ev_user_passkey_request ev;
4147
4148 BT_DBG("%s", hdev->name);
4149
Johan Hedberg272d90d2012-02-09 15:26:12 +02004150 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004151 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004152
4153 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004154 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004155}
4156
Brian Gix0df4c182011-11-16 13:53:13 -08004157static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004158 u8 link_type, u8 addr_type, u8 status,
4159 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004160{
4161 struct pending_cmd *cmd;
4162 struct mgmt_rp_user_confirm_reply rp;
4163 int err;
4164
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004165 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004166 if (!cmd)
4167 return -ENOENT;
4168
Johan Hedberg272d90d2012-02-09 15:26:12 +02004169 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004170 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004171 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004172 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004173
Johan Hedberga664b5b2011-02-19 12:06:02 -03004174 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004175
4176 return err;
4177}
4178
Johan Hedberg744cf192011-11-08 20:40:14 +02004179int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004180 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004181{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004182 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004183 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004184}
4185
Johan Hedberg272d90d2012-02-09 15:26:12 +02004186int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004187 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004188{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004189 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004190 status,
4191 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004192}
Johan Hedberg2a611692011-02-19 12:06:00 -03004193
Brian Gix604086b2011-11-23 08:28:33 -08004194int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004195 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004196{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004197 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004198 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004199}
4200
Johan Hedberg272d90d2012-02-09 15:26:12 +02004201int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004202 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004203{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004204 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004205 status,
4206 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004207}
4208
Johan Hedberg92a25252012-09-06 18:39:26 +03004209int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4210 u8 link_type, u8 addr_type, u32 passkey,
4211 u8 entered)
4212{
4213 struct mgmt_ev_passkey_notify ev;
4214
4215 BT_DBG("%s", hdev->name);
4216
4217 bacpy(&ev.addr.bdaddr, bdaddr);
4218 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4219 ev.passkey = __cpu_to_le32(passkey);
4220 ev.entered = entered;
4221
4222 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4223}
4224
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004225int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004226 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004227{
4228 struct mgmt_ev_auth_failed ev;
4229
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004230 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004231 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004232 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004233
Johan Hedberg744cf192011-11-08 20:40:14 +02004234 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004235}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004236
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004237int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4238{
4239 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004240 bool changed = false;
4241 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004242
4243 if (status) {
4244 u8 mgmt_err = mgmt_status(status);
4245 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004246 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004247 return 0;
4248 }
4249
Johan Hedberg47990ea2012-02-22 11:58:37 +02004250 if (test_bit(HCI_AUTH, &hdev->flags)) {
4251 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4252 changed = true;
4253 } else {
4254 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4255 changed = true;
4256 }
4257
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004258 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004259 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004260
Johan Hedberg47990ea2012-02-22 11:58:37 +02004261 if (changed)
4262 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004263
4264 if (match.sk)
4265 sock_put(match.sk);
4266
4267 return err;
4268}
4269
Johan Hedberg890ea892013-03-15 17:06:52 -05004270static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004271{
Johan Hedberg890ea892013-03-15 17:06:52 -05004272 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004273 struct hci_cp_write_eir cp;
4274
Johan Hedberg976eb202012-10-24 21:12:01 +03004275 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004276 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004277
Johan Hedbergc80da272012-02-22 15:38:48 +02004278 memset(hdev->eir, 0, sizeof(hdev->eir));
4279
Johan Hedbergcacaf522012-02-21 00:52:42 +02004280 memset(&cp, 0, sizeof(cp));
4281
Johan Hedberg890ea892013-03-15 17:06:52 -05004282 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004283}
4284
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004285int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004286{
4287 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004288 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004289 bool changed = false;
4290 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004291
4292 if (status) {
4293 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004294
4295 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004296 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004297 err = new_settings(hdev, NULL);
4298
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004299 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4300 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004301
4302 return err;
4303 }
4304
4305 if (enable) {
4306 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4307 changed = true;
4308 } else {
4309 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4310 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004311 }
4312
4313 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4314
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004315 if (changed)
4316 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004317
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004318 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004319 sock_put(match.sk);
4320
Johan Hedberg890ea892013-03-15 17:06:52 -05004321 hci_req_init(&req, hdev);
4322
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004323 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004324 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004325 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004326 clear_eir(&req);
4327
4328 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004329
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004330 return err;
4331}
4332
Johan Hedberg92da6092013-03-15 17:06:55 -05004333static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004334{
4335 struct cmd_lookup *match = data;
4336
Johan Hedberg90e70452012-02-23 23:09:40 +02004337 if (match->sk == NULL) {
4338 match->sk = cmd->sk;
4339 sock_hold(match->sk);
4340 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004341}
4342
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004343int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004344 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004345{
Johan Hedberg90e70452012-02-23 23:09:40 +02004346 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4347 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004348
Johan Hedberg92da6092013-03-15 17:06:55 -05004349 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4350 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4351 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004352
4353 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004354 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4355 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004356
4357 if (match.sk)
4358 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004359
4360 return err;
4361}
4362
Johan Hedberg744cf192011-11-08 20:40:14 +02004363int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004364{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004365 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004366 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004367
Johan Hedberg13928972013-03-15 17:07:00 -05004368 if (status)
4369 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004370
4371 memset(&ev, 0, sizeof(ev));
4372 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004373 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004374
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004375 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004376 if (!cmd) {
4377 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004378
Johan Hedberg13928972013-03-15 17:07:00 -05004379 /* If this is a HCI command related to powering on the
4380 * HCI dev don't send any mgmt signals.
4381 */
4382 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4383 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004384 }
4385
Johan Hedberg13928972013-03-15 17:07:00 -05004386 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4387 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004388}
Szymon Jancc35938b2011-03-22 13:12:21 +01004389
Johan Hedberg744cf192011-11-08 20:40:14 +02004390int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004391 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004392{
4393 struct pending_cmd *cmd;
4394 int err;
4395
Johan Hedberg744cf192011-11-08 20:40:14 +02004396 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004397
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004398 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004399 if (!cmd)
4400 return -ENOENT;
4401
4402 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004403 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4404 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004405 } else {
4406 struct mgmt_rp_read_local_oob_data rp;
4407
4408 memcpy(rp.hash, hash, sizeof(rp.hash));
4409 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4410
Johan Hedberg744cf192011-11-08 20:40:14 +02004411 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004412 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4413 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004414 }
4415
4416 mgmt_pending_remove(cmd);
4417
4418 return err;
4419}
Johan Hedberge17acd42011-03-30 23:57:16 +03004420
Johan Hedberg48264f02011-11-09 13:58:58 +02004421int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004422 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4423 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004424{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004425 char buf[512];
4426 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004427 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004428
Andre Guedes12602d02013-04-30 15:29:40 -03004429 if (!hci_discovery_active(hdev))
4430 return -EPERM;
4431
Johan Hedberg1dc06092012-01-15 21:01:23 +02004432 /* Leave 5 bytes for a potential CoD field */
4433 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004434 return -EINVAL;
4435
Johan Hedberg1dc06092012-01-15 21:01:23 +02004436 memset(buf, 0, sizeof(buf));
4437
Johan Hedberge319d2e2012-01-15 19:51:59 +02004438 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004439 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004440 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004441 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304442 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004443 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304444 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004445
Johan Hedberg1dc06092012-01-15 21:01:23 +02004446 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004447 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004448
Johan Hedberg1dc06092012-01-15 21:01:23 +02004449 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4450 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004451 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004452
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004453 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004454 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004455
Johan Hedberge319d2e2012-01-15 19:51:59 +02004456 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004457}
Johan Hedberga88a9652011-03-30 13:18:12 +03004458
Johan Hedbergb644ba32012-01-17 21:48:47 +02004459int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004460 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004461{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004462 struct mgmt_ev_device_found *ev;
4463 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4464 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004465
Johan Hedbergb644ba32012-01-17 21:48:47 +02004466 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004467
Johan Hedbergb644ba32012-01-17 21:48:47 +02004468 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004469
Johan Hedbergb644ba32012-01-17 21:48:47 +02004470 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004471 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004472 ev->rssi = rssi;
4473
4474 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004475 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004476
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004477 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004478
Johan Hedberg053c7e02012-02-04 00:06:00 +02004479 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004480 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004481}
Johan Hedberg314b2382011-04-27 10:29:57 -04004482
Johan Hedberg744cf192011-11-08 20:40:14 +02004483int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004484{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004485 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004486 struct pending_cmd *cmd;
4487
Andre Guedes343fb142011-11-22 17:14:19 -03004488 BT_DBG("%s discovering %u", hdev->name, discovering);
4489
Johan Hedberg164a6e72011-11-01 17:06:44 +02004490 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004491 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004492 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004493 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004494
4495 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004496 u8 type = hdev->discovery.type;
4497
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004498 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4499 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004500 mgmt_pending_remove(cmd);
4501 }
4502
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004503 memset(&ev, 0, sizeof(ev));
4504 ev.type = hdev->discovery.type;
4505 ev.discovering = discovering;
4506
4507 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004508}
Antti Julku5e762442011-08-25 16:48:02 +03004509
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004510int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004511{
4512 struct pending_cmd *cmd;
4513 struct mgmt_ev_device_blocked ev;
4514
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004515 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004516
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004517 bacpy(&ev.addr.bdaddr, bdaddr);
4518 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004519
Johan Hedberg744cf192011-11-08 20:40:14 +02004520 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004521 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004522}
4523
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004524int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004525{
4526 struct pending_cmd *cmd;
4527 struct mgmt_ev_device_unblocked ev;
4528
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004529 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004530
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004531 bacpy(&ev.addr.bdaddr, bdaddr);
4532 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004533
Johan Hedberg744cf192011-11-08 20:40:14 +02004534 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004535 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004536}