blob: 4c3984ee11140b6449f78dec203219177980e941 [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
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060038#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
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;
382 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200383
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384 if (enable_hs)
385 settings |= MGMT_SETTING_HS;
386
Andre Guedesc383ddc2012-07-24 15:03:47 -0300387 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200388 settings |= MGMT_SETTING_LE;
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
Andre Guedesed3fa312012-07-24 15:03:46 -0300412 if (lmp_bredr_capable(hdev))
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 Hedberg84bde9d2012-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 Hedberg69ab39e2011-12-15 00:47:35 +0200427 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200428}
429
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300430#define PNP_INFO_SVCLASS_ID 0x1200
431
Johan Hedberg213202e2013-01-27 00:31:33 +0200432static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
433{
434 u8 *ptr = data, *uuids_start = NULL;
435 struct bt_uuid *uuid;
436
437 if (len < 4)
438 return ptr;
439
440 list_for_each_entry(uuid, &hdev->uuids, list) {
441 u16 uuid16;
442
443 if (uuid->size != 16)
444 continue;
445
446 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
447 if (uuid16 < 0x1100)
448 continue;
449
450 if (uuid16 == PNP_INFO_SVCLASS_ID)
451 continue;
452
453 if (!uuids_start) {
454 uuids_start = ptr;
455 uuids_start[0] = 1;
456 uuids_start[1] = EIR_UUID16_ALL;
457 ptr += 2;
458 }
459
460 /* Stop if not enough space to put next UUID */
461 if ((ptr - data) + sizeof(u16) > len) {
462 uuids_start[1] = EIR_UUID16_SOME;
463 break;
464 }
465
466 *ptr++ = (uuid16 & 0x00ff);
467 *ptr++ = (uuid16 & 0xff00) >> 8;
468 uuids_start[0] += sizeof(uuid16);
469 }
470
471 return ptr;
472}
473
Johan Hedbergcdf19632013-01-27 00:31:34 +0200474static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
475{
476 u8 *ptr = data, *uuids_start = NULL;
477 struct bt_uuid *uuid;
478
479 if (len < 6)
480 return ptr;
481
482 list_for_each_entry(uuid, &hdev->uuids, list) {
483 if (uuid->size != 32)
484 continue;
485
486 if (!uuids_start) {
487 uuids_start = ptr;
488 uuids_start[0] = 1;
489 uuids_start[1] = EIR_UUID32_ALL;
490 ptr += 2;
491 }
492
493 /* Stop if not enough space to put next UUID */
494 if ((ptr - data) + sizeof(u32) > len) {
495 uuids_start[1] = EIR_UUID32_SOME;
496 break;
497 }
498
499 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
500 ptr += sizeof(u32);
501 uuids_start[0] += sizeof(u32);
502 }
503
504 return ptr;
505}
506
Johan Hedbergc00d5752013-01-27 00:31:35 +0200507static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
508{
509 u8 *ptr = data, *uuids_start = NULL;
510 struct bt_uuid *uuid;
511
512 if (len < 18)
513 return ptr;
514
515 list_for_each_entry(uuid, &hdev->uuids, list) {
516 if (uuid->size != 128)
517 continue;
518
519 if (!uuids_start) {
520 uuids_start = ptr;
521 uuids_start[0] = 1;
522 uuids_start[1] = EIR_UUID128_ALL;
523 ptr += 2;
524 }
525
526 /* Stop if not enough space to put next UUID */
527 if ((ptr - data) + 16 > len) {
528 uuids_start[1] = EIR_UUID128_SOME;
529 break;
530 }
531
532 memcpy(ptr, uuid->uuid, 16);
533 ptr += 16;
534 uuids_start[0] += 16;
535 }
536
537 return ptr;
538}
539
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300540static void create_eir(struct hci_dev *hdev, u8 *data)
541{
542 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300543 size_t name_len;
544
545 name_len = strlen(hdev->dev_name);
546
547 if (name_len > 0) {
548 /* EIR Data type */
549 if (name_len > 48) {
550 name_len = 48;
551 ptr[1] = EIR_NAME_SHORT;
552 } else
553 ptr[1] = EIR_NAME_COMPLETE;
554
555 /* EIR Data length */
556 ptr[0] = name_len + 1;
557
558 memcpy(ptr + 2, hdev->dev_name, name_len);
559
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300560 ptr += (name_len + 2);
561 }
562
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100563 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700564 ptr[0] = 2;
565 ptr[1] = EIR_TX_POWER;
566 ptr[2] = (u8) hdev->inq_tx_power;
567
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700568 ptr += 3;
569 }
570
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700571 if (hdev->devid_source > 0) {
572 ptr[0] = 9;
573 ptr[1] = EIR_DEVICE_ID;
574
575 put_unaligned_le16(hdev->devid_source, ptr + 2);
576 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
577 put_unaligned_le16(hdev->devid_product, ptr + 6);
578 put_unaligned_le16(hdev->devid_version, ptr + 8);
579
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700580 ptr += 10;
581 }
582
Johan Hedberg213202e2013-01-27 00:31:33 +0200583 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200584 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200585 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300586}
587
Johan Hedberg890ea892013-03-15 17:06:52 -0500588static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300589{
Johan Hedberg890ea892013-03-15 17:06:52 -0500590 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300591 struct hci_cp_write_eir cp;
592
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200593 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200595
Johan Hedberg976eb202012-10-24 21:12:01 +0300596 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500597 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300598
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200599 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200602 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500603 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300604
605 memset(&cp, 0, sizeof(cp));
606
607 create_eir(hdev, cp.data);
608
609 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500610 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300611
612 memcpy(hdev->eir, cp.data, sizeof(cp.data));
613
Johan Hedberg890ea892013-03-15 17:06:52 -0500614 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300615}
616
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200617static u8 get_service_classes(struct hci_dev *hdev)
618{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300619 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620 u8 val = 0;
621
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300622 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200623 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624
625 return val;
626}
627
Johan Hedberg890ea892013-03-15 17:06:52 -0500628static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200629{
Johan Hedberg890ea892013-03-15 17:06:52 -0500630 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200631 u8 cod[3];
632
633 BT_DBG("%s", hdev->name);
634
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200635 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500636 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200637
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200638 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500639 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200640
641 cod[0] = hdev->minor_class;
642 cod[1] = hdev->major_class;
643 cod[2] = get_service_classes(hdev);
644
645 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500646 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200647
Johan Hedberg890ea892013-03-15 17:06:52 -0500648 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200649}
650
Johan Hedberg7d785252011-12-15 00:47:39 +0200651static void service_cache_off(struct work_struct *work)
652{
653 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300654 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500655 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200656
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200657 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200658 return;
659
Johan Hedberg890ea892013-03-15 17:06:52 -0500660 hci_req_init(&req, hdev);
661
Johan Hedberg7d785252011-12-15 00:47:39 +0200662 hci_dev_lock(hdev);
663
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 update_eir(&req);
665 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200666
667 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500668
669 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200670}
671
Johan Hedberg6a919082012-02-28 06:17:26 +0200672static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200673{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200674 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200675 return;
676
Johan Hedberg4f87da82012-03-02 19:55:56 +0200677 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200678
Johan Hedberg4f87da82012-03-02 19:55:56 +0200679 /* Non-mgmt controlled devices get this bit set
680 * implicitly so that pairing works for them, however
681 * for mgmt we require user-space to explicitly enable
682 * it
683 */
684 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200685}
686
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200687static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300688 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200689{
690 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200691
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200692 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200693
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300694 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedberg03811012010-12-08 00:21:06 +0200696 memset(&rp, 0, sizeof(rp));
697
Johan Hedberg03811012010-12-08 00:21:06 +0200698 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200699
700 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200701 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200702
703 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
704 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
705
706 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200707
708 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200709 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200710
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300711 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200712
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200713 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300714 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200715}
716
717static void mgmt_pending_free(struct pending_cmd *cmd)
718{
719 sock_put(cmd->sk);
720 kfree(cmd->param);
721 kfree(cmd);
722}
723
724static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300725 struct hci_dev *hdev, void *data,
726 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200727{
728 struct pending_cmd *cmd;
729
Andre Guedes12b94562012-06-07 19:05:45 -0300730 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200731 if (!cmd)
732 return NULL;
733
734 cmd->opcode = opcode;
735 cmd->index = hdev->id;
736
Andre Guedes12b94562012-06-07 19:05:45 -0300737 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200738 if (!cmd->param) {
739 kfree(cmd);
740 return NULL;
741 }
742
743 if (data)
744 memcpy(cmd->param, data, len);
745
746 cmd->sk = sk;
747 sock_hold(sk);
748
749 list_add(&cmd->list, &hdev->mgmt_pending);
750
751 return cmd;
752}
753
754static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300755 void (*cb)(struct pending_cmd *cmd,
756 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300757 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200758{
Andre Guedesa3d09352013-02-01 11:21:30 -0300759 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200760
Andre Guedesa3d09352013-02-01 11:21:30 -0300761 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200762 if (opcode > 0 && cmd->opcode != opcode)
763 continue;
764
765 cb(cmd, data);
766 }
767}
768
769static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
770{
771 struct pending_cmd *cmd;
772
773 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
774 if (cmd->opcode == opcode)
775 return cmd;
776 }
777
778 return NULL;
779}
780
781static void mgmt_pending_remove(struct pending_cmd *cmd)
782{
783 list_del(&cmd->list);
784 mgmt_pending_free(cmd);
785}
786
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200788{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200789 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200790
Johan Hedbergaee9b212012-02-18 15:07:59 +0200791 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300792 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200793}
794
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200795static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300798 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200799 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200800 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200801
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200802 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200803
Johan Hedberga7e80f22013-01-09 16:05:19 +0200804 if (cp->val != 0x00 && cp->val != 0x01)
805 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
806 MGMT_STATUS_INVALID_PARAMS);
807
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300808 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200809
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300810 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
811 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
812 MGMT_STATUS_BUSY);
813 goto failed;
814 }
815
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100816 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
817 cancel_delayed_work(&hdev->power_off);
818
819 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200820 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
821 data, len);
822 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100823 goto failed;
824 }
825 }
826
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200827 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200828 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200829 goto failed;
830 }
831
Johan Hedberg03811012010-12-08 00:21:06 +0200832 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
833 if (!cmd) {
834 err = -ENOMEM;
835 goto failed;
836 }
837
838 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200839 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200840 else
Johan Hedberg19202572013-01-14 22:33:51 +0200841 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200842
843 err = 0;
844
845failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300846 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200847 return err;
848}
849
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300850static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
851 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200852{
853 struct sk_buff *skb;
854 struct mgmt_hdr *hdr;
855
Andre Guedes790eff42012-06-07 19:05:46 -0300856 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200857 if (!skb)
858 return -ENOMEM;
859
860 hdr = (void *) skb_put(skb, sizeof(*hdr));
861 hdr->opcode = cpu_to_le16(event);
862 if (hdev)
863 hdr->index = cpu_to_le16(hdev->id);
864 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530865 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200866 hdr->len = cpu_to_le16(data_len);
867
868 if (data)
869 memcpy(skb_put(skb, data_len), data, data_len);
870
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100871 /* Time stamp */
872 __net_timestamp(skb);
873
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200874 hci_send_to_control(skb, skip_sk);
875 kfree_skb(skb);
876
877 return 0;
878}
879
880static int new_settings(struct hci_dev *hdev, struct sock *skip)
881{
882 __le32 ev;
883
884 ev = cpu_to_le32(get_current_settings(hdev));
885
886 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
887}
888
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300889struct cmd_lookup {
890 struct sock *sk;
891 struct hci_dev *hdev;
892 u8 mgmt_status;
893};
894
895static void settings_rsp(struct pending_cmd *cmd, void *data)
896{
897 struct cmd_lookup *match = data;
898
899 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
900
901 list_del(&cmd->list);
902
903 if (match->sk == NULL) {
904 match->sk = cmd->sk;
905 sock_hold(match->sk);
906 }
907
908 mgmt_pending_free(cmd);
909}
910
911static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
912{
913 u8 *status = data;
914
915 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
916 mgmt_pending_remove(cmd);
917}
918
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200919static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300920 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200921{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300922 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200923 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200924 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200925 u8 scan;
926 int err;
927
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200928 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200929
Johan Hedberg33c525c2012-10-24 21:11:58 +0300930 if (!lmp_bredr_capable(hdev))
931 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
932 MGMT_STATUS_NOT_SUPPORTED);
933
Johan Hedberga7e80f22013-01-09 16:05:19 +0200934 if (cp->val != 0x00 && cp->val != 0x01)
935 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
936 MGMT_STATUS_INVALID_PARAMS);
937
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700938 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100939 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200940 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300941 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200942
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300943 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200944
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200945 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200946 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300947 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200948 goto failed;
949 }
950
951 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300952 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200953 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300954 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200955 goto failed;
956 }
957
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200958 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200959 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300960 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200961 goto failed;
962 }
963
964 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200965 bool changed = false;
966
967 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
968 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
969 changed = true;
970 }
971
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200972 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200973 if (err < 0)
974 goto failed;
975
976 if (changed)
977 err = new_settings(hdev, sk);
978
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 goto failed;
980 }
981
982 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100983 if (hdev->discov_timeout > 0) {
984 cancel_delayed_work(&hdev->discov_off);
985 hdev->discov_timeout = 0;
986 }
987
988 if (cp->val && timeout > 0) {
989 hdev->discov_timeout = timeout;
990 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
991 msecs_to_jiffies(hdev->discov_timeout * 1000));
992 }
993
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200994 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200995 goto failed;
996 }
997
998 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
999 if (!cmd) {
1000 err = -ENOMEM;
1001 goto failed;
1002 }
1003
1004 scan = SCAN_PAGE;
1005
1006 if (cp->val)
1007 scan |= SCAN_INQUIRY;
1008 else
1009 cancel_delayed_work(&hdev->discov_off);
1010
1011 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1012 if (err < 0)
1013 mgmt_pending_remove(cmd);
1014
Johan Hedberg03811012010-12-08 00:21:06 +02001015 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001016 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001017
1018failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001019 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001020 return err;
1021}
1022
Johan Hedberg406d7802013-03-15 17:07:09 -05001023static void write_fast_connectable(struct hci_request *req, bool enable)
1024{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001025 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001026 struct hci_cp_write_page_scan_activity acp;
1027 u8 type;
1028
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001029 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1030 return;
1031
Johan Hedberg406d7802013-03-15 17:07:09 -05001032 if (enable) {
1033 type = PAGE_SCAN_TYPE_INTERLACED;
1034
1035 /* 160 msec page scan interval */
1036 acp.interval = __constant_cpu_to_le16(0x0100);
1037 } else {
1038 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1039
1040 /* default 1.28 sec page scan */
1041 acp.interval = __constant_cpu_to_le16(0x0800);
1042 }
1043
1044 acp.window = __constant_cpu_to_le16(0x0012);
1045
Johan Hedbergbd98b992013-03-15 17:07:13 -05001046 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1047 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1048 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1049 sizeof(acp), &acp);
1050
1051 if (hdev->page_scan_type != type)
1052 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001053}
1054
Johan Hedberg2b76f452013-03-15 17:07:04 -05001055static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1056{
1057 struct pending_cmd *cmd;
1058
1059 BT_DBG("status 0x%02x", status);
1060
1061 hci_dev_lock(hdev);
1062
1063 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1064 if (!cmd)
1065 goto unlock;
1066
1067 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1068
1069 mgmt_pending_remove(cmd);
1070
1071unlock:
1072 hci_dev_unlock(hdev);
1073}
1074
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001075static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001076 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001077{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001078 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001079 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001080 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001081 u8 scan;
1082 int err;
1083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001084 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001085
Johan Hedberg33c525c2012-10-24 21:11:58 +03001086 if (!lmp_bredr_capable(hdev))
1087 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1088 MGMT_STATUS_NOT_SUPPORTED);
1089
Johan Hedberga7e80f22013-01-09 16:05:19 +02001090 if (cp->val != 0x00 && cp->val != 0x01)
1091 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1092 MGMT_STATUS_INVALID_PARAMS);
1093
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001094 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001095
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001096 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001097 bool changed = false;
1098
1099 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1100 changed = true;
1101
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001102 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001103 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001104 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001105 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1106 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1107 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001108
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001109 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001110 if (err < 0)
1111 goto failed;
1112
1113 if (changed)
1114 err = new_settings(hdev, sk);
1115
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001116 goto failed;
1117 }
1118
1119 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001120 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001121 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001122 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001123 goto failed;
1124 }
1125
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001126 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001127 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001128 goto failed;
1129 }
1130
1131 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1132 if (!cmd) {
1133 err = -ENOMEM;
1134 goto failed;
1135 }
1136
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001137 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001138 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001139 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001140 scan = 0;
1141
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001142 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001143 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001144 cancel_delayed_work(&hdev->discov_off);
1145 }
1146
Johan Hedberg2b76f452013-03-15 17:07:04 -05001147 hci_req_init(&req, hdev);
1148
1149 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1150
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001151 /* If we're going from non-connectable to connectable or
1152 * vice-versa when fast connectable is enabled ensure that fast
1153 * connectable gets disabled. write_fast_connectable won't do
1154 * anything if the page scan parameters are already what they
1155 * should be.
1156 */
1157 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001158 write_fast_connectable(&req, false);
1159
Johan Hedberg2b76f452013-03-15 17:07:04 -05001160 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001161 if (err < 0)
1162 mgmt_pending_remove(cmd);
1163
1164failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001165 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166 return err;
1167}
1168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001169static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001170 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001171{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001172 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001173 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001175 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001176
Johan Hedberga7e80f22013-01-09 16:05:19 +02001177 if (cp->val != 0x00 && cp->val != 0x01)
1178 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1179 MGMT_STATUS_INVALID_PARAMS);
1180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001181 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001182
1183 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001184 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001185 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001186 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001188 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001189 if (err < 0)
1190 goto failed;
1191
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001192 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193
1194failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001195 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196 return err;
1197}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001198
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001199static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1200 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001201{
1202 struct mgmt_mode *cp = data;
1203 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001204 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001205 int err;
1206
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001207 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001208
Johan Hedberg33c525c2012-10-24 21:11:58 +03001209 if (!lmp_bredr_capable(hdev))
1210 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1211 MGMT_STATUS_NOT_SUPPORTED);
1212
Johan Hedberga7e80f22013-01-09 16:05:19 +02001213 if (cp->val != 0x00 && cp->val != 0x01)
1214 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1215 MGMT_STATUS_INVALID_PARAMS);
1216
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001217 hci_dev_lock(hdev);
1218
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001219 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001220 bool changed = false;
1221
1222 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001223 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001224 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1225 changed = true;
1226 }
1227
1228 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1229 if (err < 0)
1230 goto failed;
1231
1232 if (changed)
1233 err = new_settings(hdev, sk);
1234
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001235 goto failed;
1236 }
1237
1238 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001239 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001240 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001241 goto failed;
1242 }
1243
1244 val = !!cp->val;
1245
1246 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1247 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1248 goto failed;
1249 }
1250
1251 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1252 if (!cmd) {
1253 err = -ENOMEM;
1254 goto failed;
1255 }
1256
1257 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1258 if (err < 0) {
1259 mgmt_pending_remove(cmd);
1260 goto failed;
1261 }
1262
1263failed:
1264 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001265 return err;
1266}
1267
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001268static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001269{
1270 struct mgmt_mode *cp = data;
1271 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001272 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001273 int err;
1274
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001275 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001276
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001277 if (!lmp_ssp_capable(hdev))
1278 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1279 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001280
Johan Hedberga7e80f22013-01-09 16:05:19 +02001281 if (cp->val != 0x00 && cp->val != 0x01)
1282 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1283 MGMT_STATUS_INVALID_PARAMS);
1284
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001285 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001286
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001287 val = !!cp->val;
1288
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001289 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001290 bool changed = false;
1291
1292 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1293 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1294 changed = true;
1295 }
1296
1297 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1298 if (err < 0)
1299 goto failed;
1300
1301 if (changed)
1302 err = new_settings(hdev, sk);
1303
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001304 goto failed;
1305 }
1306
1307 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001308 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1309 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001310 goto failed;
1311 }
1312
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001313 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1314 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1315 goto failed;
1316 }
1317
1318 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1319 if (!cmd) {
1320 err = -ENOMEM;
1321 goto failed;
1322 }
1323
1324 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1325 if (err < 0) {
1326 mgmt_pending_remove(cmd);
1327 goto failed;
1328 }
1329
1330failed:
1331 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001332 return err;
1333}
1334
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001335static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001336{
1337 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001338
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001339 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001340
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001341 if (!enable_hs)
1342 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001344
Johan Hedberga7e80f22013-01-09 16:05:19 +02001345 if (cp->val != 0x00 && cp->val != 0x01)
1346 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1347 MGMT_STATUS_INVALID_PARAMS);
1348
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001349 if (cp->val)
1350 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1351 else
1352 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001354 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001355}
1356
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001357static void le_enable_complete(struct hci_dev *hdev, u8 status)
1358{
1359 struct cmd_lookup match = { NULL, hdev };
1360
1361 if (status) {
1362 u8 mgmt_err = mgmt_status(status);
1363
1364 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1365 &mgmt_err);
1366 return;
1367 }
1368
1369 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1370
1371 new_settings(hdev, match.sk);
1372
1373 if (match.sk)
1374 sock_put(match.sk);
1375}
1376
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001377static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001378{
1379 struct mgmt_mode *cp = data;
1380 struct hci_cp_write_le_host_supported hci_cp;
1381 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001382 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001383 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001384 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001385
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001386 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001387
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001388 if (!lmp_le_capable(hdev))
1389 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1390 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001391
Johan Hedberga7e80f22013-01-09 16:05:19 +02001392 if (cp->val != 0x00 && cp->val != 0x01)
1393 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1394 MGMT_STATUS_INVALID_PARAMS);
1395
Johan Hedbergc73eee92013-04-19 18:35:21 +03001396 /* LE-only devices do not allow toggling LE on/off */
1397 if (!lmp_bredr_capable(hdev))
1398 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1399 MGMT_STATUS_REJECTED);
1400
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001401 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001402
1403 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001404 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001405
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001406 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001407 bool changed = false;
1408
1409 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1410 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1411 changed = true;
1412 }
1413
1414 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1415 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001416 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001417
1418 if (changed)
1419 err = new_settings(hdev, sk);
1420
Johan Hedberg1de028c2012-02-29 19:55:35 -08001421 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001422 }
1423
1424 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001425 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001426 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001427 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001428 }
1429
1430 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1431 if (!cmd) {
1432 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001433 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001434 }
1435
1436 memset(&hci_cp, 0, sizeof(hci_cp));
1437
1438 if (val) {
1439 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001440 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001441 }
1442
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001443 hci_req_init(&req, hdev);
1444
1445 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1446 &hci_cp);
1447
1448 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301449 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001450 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001451
Johan Hedberg1de028c2012-02-29 19:55:35 -08001452unlock:
1453 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001454 return err;
1455}
1456
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001457/* This is a helper function to test for pending mgmt commands that can
1458 * cause CoD or EIR HCI commands. We can only allow one such pending
1459 * mgmt command at a time since otherwise we cannot easily track what
1460 * the current values are, will be, and based on that calculate if a new
1461 * HCI command needs to be sent and if yes with what value.
1462 */
1463static bool pending_eir_or_class(struct hci_dev *hdev)
1464{
1465 struct pending_cmd *cmd;
1466
1467 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1468 switch (cmd->opcode) {
1469 case MGMT_OP_ADD_UUID:
1470 case MGMT_OP_REMOVE_UUID:
1471 case MGMT_OP_SET_DEV_CLASS:
1472 case MGMT_OP_SET_POWERED:
1473 return true;
1474 }
1475 }
1476
1477 return false;
1478}
1479
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001480static const u8 bluetooth_base_uuid[] = {
1481 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1482 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1483};
1484
1485static u8 get_uuid_size(const u8 *uuid)
1486{
1487 u32 val;
1488
1489 if (memcmp(uuid, bluetooth_base_uuid, 12))
1490 return 128;
1491
1492 val = get_unaligned_le32(&uuid[12]);
1493 if (val > 0xffff)
1494 return 32;
1495
1496 return 16;
1497}
1498
Johan Hedberg92da6092013-03-15 17:06:55 -05001499static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1500{
1501 struct pending_cmd *cmd;
1502
1503 hci_dev_lock(hdev);
1504
1505 cmd = mgmt_pending_find(mgmt_op, hdev);
1506 if (!cmd)
1507 goto unlock;
1508
1509 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1510 hdev->dev_class, 3);
1511
1512 mgmt_pending_remove(cmd);
1513
1514unlock:
1515 hci_dev_unlock(hdev);
1516}
1517
1518static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1519{
1520 BT_DBG("status 0x%02x", status);
1521
1522 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1523}
1524
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001525static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001526{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001527 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001528 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001529 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001530 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001531 int err;
1532
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001533 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001534
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001535 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001536
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001537 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001538 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001539 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001540 goto failed;
1541 }
1542
Andre Guedes92c4c202012-06-07 19:05:44 -03001543 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001544 if (!uuid) {
1545 err = -ENOMEM;
1546 goto failed;
1547 }
1548
1549 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001550 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001551 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001552
Johan Hedbergde66aa62013-01-27 00:31:27 +02001553 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001554
Johan Hedberg890ea892013-03-15 17:06:52 -05001555 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001556
Johan Hedberg890ea892013-03-15 17:06:52 -05001557 update_class(&req);
1558 update_eir(&req);
1559
Johan Hedberg92da6092013-03-15 17:06:55 -05001560 err = hci_req_run(&req, add_uuid_complete);
1561 if (err < 0) {
1562 if (err != -ENODATA)
1563 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001564
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001565 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001566 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001567 goto failed;
1568 }
1569
1570 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001571 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001572 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001573 goto failed;
1574 }
1575
1576 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001577
1578failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001579 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001580 return err;
1581}
1582
Johan Hedberg24b78d02012-02-23 23:24:30 +02001583static bool enable_service_cache(struct hci_dev *hdev)
1584{
1585 if (!hdev_is_powered(hdev))
1586 return false;
1587
1588 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001589 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1590 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001591 return true;
1592 }
1593
1594 return false;
1595}
1596
Johan Hedberg92da6092013-03-15 17:06:55 -05001597static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1598{
1599 BT_DBG("status 0x%02x", status);
1600
1601 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1602}
1603
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001604static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001605 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001606{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001607 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001608 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001609 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001610 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 -05001611 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001612 int err, found;
1613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001614 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001615
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001616 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001617
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001618 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001619 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001620 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001621 goto unlock;
1622 }
1623
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001624 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1625 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001626
Johan Hedberg24b78d02012-02-23 23:24:30 +02001627 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001628 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001629 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001630 goto unlock;
1631 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001632
Johan Hedberg9246a862012-02-23 21:33:16 +02001633 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001634 }
1635
1636 found = 0;
1637
Johan Hedberg056341c2013-01-27 00:31:30 +02001638 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001639 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1640 continue;
1641
1642 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001643 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001644 found++;
1645 }
1646
1647 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001648 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001649 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001650 goto unlock;
1651 }
1652
Johan Hedberg9246a862012-02-23 21:33:16 +02001653update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001654 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001655
Johan Hedberg890ea892013-03-15 17:06:52 -05001656 update_class(&req);
1657 update_eir(&req);
1658
Johan Hedberg92da6092013-03-15 17:06:55 -05001659 err = hci_req_run(&req, remove_uuid_complete);
1660 if (err < 0) {
1661 if (err != -ENODATA)
1662 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001664 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001665 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001666 goto unlock;
1667 }
1668
1669 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001670 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001671 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001672 goto unlock;
1673 }
1674
1675 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001676
1677unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001678 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001679 return err;
1680}
1681
Johan Hedberg92da6092013-03-15 17:06:55 -05001682static void set_class_complete(struct hci_dev *hdev, u8 status)
1683{
1684 BT_DBG("status 0x%02x", status);
1685
1686 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1687}
1688
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001689static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001690 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001691{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001692 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001693 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001694 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001695 int err;
1696
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001697 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001698
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001699 if (!lmp_bredr_capable(hdev))
1700 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1701 MGMT_STATUS_NOT_SUPPORTED);
1702
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001703 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001704
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001705 if (pending_eir_or_class(hdev)) {
1706 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1707 MGMT_STATUS_BUSY);
1708 goto unlock;
1709 }
1710
1711 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1712 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1713 MGMT_STATUS_INVALID_PARAMS);
1714 goto unlock;
1715 }
1716
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001717 hdev->major_class = cp->major;
1718 hdev->minor_class = cp->minor;
1719
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001720 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001721 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001723 goto unlock;
1724 }
1725
Johan Hedberg890ea892013-03-15 17:06:52 -05001726 hci_req_init(&req, hdev);
1727
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001728 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001729 hci_dev_unlock(hdev);
1730 cancel_delayed_work_sync(&hdev->service_cache);
1731 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001732 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001733 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001734
Johan Hedberg890ea892013-03-15 17:06:52 -05001735 update_class(&req);
1736
Johan Hedberg92da6092013-03-15 17:06:55 -05001737 err = hci_req_run(&req, set_class_complete);
1738 if (err < 0) {
1739 if (err != -ENODATA)
1740 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001741
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001742 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001743 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001744 goto unlock;
1745 }
1746
1747 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001748 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001749 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001750 goto unlock;
1751 }
1752
1753 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001754
Johan Hedbergb5235a62012-02-21 14:32:24 +02001755unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001756 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001757 return err;
1758}
1759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001760static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001761 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001762{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001763 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001764 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001765 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001766
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001767 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001768
Johan Hedberg86742e12011-11-07 23:13:38 +02001769 expected_len = sizeof(*cp) + key_count *
1770 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001771 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001772 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001773 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001774 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001775 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001776 }
1777
Johan Hedberg4ae14302013-01-20 14:27:13 +02001778 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1779 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1780 MGMT_STATUS_INVALID_PARAMS);
1781
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001782 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001783 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001784
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001785 for (i = 0; i < key_count; i++) {
1786 struct mgmt_link_key_info *key = &cp->keys[i];
1787
1788 if (key->addr.type != BDADDR_BREDR)
1789 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1790 MGMT_STATUS_INVALID_PARAMS);
1791 }
1792
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001793 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001794
1795 hci_link_keys_clear(hdev);
1796
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001797 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001798 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001799 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001800 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001801
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001802 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001803 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001804
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001805 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001806 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001807 }
1808
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001809 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001812
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001813 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001814}
1815
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001816static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001817 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001818{
1819 struct mgmt_ev_device_unpaired ev;
1820
1821 bacpy(&ev.addr.bdaddr, bdaddr);
1822 ev.addr.type = addr_type;
1823
1824 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001825 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001826}
1827
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001828static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001829 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001830{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001831 struct mgmt_cp_unpair_device *cp = data;
1832 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001833 struct hci_cp_disconnect dc;
1834 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001835 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001836 int err;
1837
Johan Hedberga8a1d192011-11-10 15:54:38 +02001838 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001839 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1840 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001841
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001842 if (!bdaddr_type_is_valid(cp->addr.type))
1843 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1844 MGMT_STATUS_INVALID_PARAMS,
1845 &rp, sizeof(rp));
1846
Johan Hedberg118da702013-01-20 14:27:20 +02001847 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1848 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1849 MGMT_STATUS_INVALID_PARAMS,
1850 &rp, sizeof(rp));
1851
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001852 hci_dev_lock(hdev);
1853
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001854 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001855 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001856 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001857 goto unlock;
1858 }
1859
Andre Guedes591f47f2012-04-24 21:02:49 -03001860 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001861 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1862 else
1863 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001864
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001865 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001866 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001867 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001868 goto unlock;
1869 }
1870
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001871 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001872 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001873 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001874 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001875 else
1876 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001877 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001878 } else {
1879 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001880 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001881
Johan Hedberga8a1d192011-11-10 15:54:38 +02001882 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001883 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001884 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001885 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001886 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001887 }
1888
Johan Hedberg124f6e32012-02-09 13:50:12 +02001889 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001890 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001891 if (!cmd) {
1892 err = -ENOMEM;
1893 goto unlock;
1894 }
1895
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001896 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001897 dc.reason = 0x13; /* Remote User Terminated Connection */
1898 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1899 if (err < 0)
1900 mgmt_pending_remove(cmd);
1901
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001902unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001903 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001904 return err;
1905}
1906
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001907static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001908 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001909{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001910 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001911 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001912 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001913 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001914 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001915 int err;
1916
1917 BT_DBG("");
1918
Johan Hedberg06a63b12013-01-20 14:27:21 +02001919 memset(&rp, 0, sizeof(rp));
1920 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1921 rp.addr.type = cp->addr.type;
1922
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001923 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001924 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1925 MGMT_STATUS_INVALID_PARAMS,
1926 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001928 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001929
1930 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001931 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1932 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001933 goto failed;
1934 }
1935
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001936 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001937 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1938 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001939 goto failed;
1940 }
1941
Andre Guedes591f47f2012-04-24 21:02:49 -03001942 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001943 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1944 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001945 else
1946 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001947
Vishal Agarwalf9607272012-06-13 05:32:43 +05301948 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001949 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1950 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001951 goto failed;
1952 }
1953
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001954 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001955 if (!cmd) {
1956 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001957 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001958 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001959
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001960 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001961 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001962
1963 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1964 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001965 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001966
1967failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001968 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001969 return err;
1970}
1971
Andre Guedes57c14772012-04-24 21:02:50 -03001972static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001973{
1974 switch (link_type) {
1975 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001976 switch (addr_type) {
1977 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001978 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001979
Johan Hedberg48264f02011-11-09 13:58:58 +02001980 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001981 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001982 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001983 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001984
Johan Hedberg4c659c32011-11-07 23:13:39 +02001985 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001986 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001987 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001988 }
1989}
1990
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001991static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1992 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001993{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001994 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001995 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001996 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001997 int err;
1998 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001999
2000 BT_DBG("");
2001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002002 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002003
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002004 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002005 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002006 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002007 goto unlock;
2008 }
2009
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002010 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002011 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2012 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002013 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002014 }
2015
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002016 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002017 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002018 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002019 err = -ENOMEM;
2020 goto unlock;
2021 }
2022
Johan Hedberg2784eb42011-01-21 13:56:35 +02002023 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002024 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002025 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2026 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002027 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002028 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002029 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002030 continue;
2031 i++;
2032 }
2033
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002034 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002035
Johan Hedberg4c659c32011-11-07 23:13:39 +02002036 /* Recalculate length in case of filtered SCO connections, etc */
2037 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002038
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002039 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002040 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002041
Johan Hedberga38528f2011-01-22 06:46:43 +02002042 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002043
2044unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002045 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002046 return err;
2047}
2048
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002049static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002050 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002051{
2052 struct pending_cmd *cmd;
2053 int err;
2054
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002055 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002056 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002057 if (!cmd)
2058 return -ENOMEM;
2059
Johan Hedbergd8457692012-02-17 14:24:57 +02002060 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002061 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002062 if (err < 0)
2063 mgmt_pending_remove(cmd);
2064
2065 return err;
2066}
2067
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002068static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002069 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002070{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002071 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002072 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002073 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002074 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002075 int err;
2076
2077 BT_DBG("");
2078
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002079 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002080
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002081 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002082 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002083 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002084 goto failed;
2085 }
2086
Johan Hedbergd8457692012-02-17 14:24:57 +02002087 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002088 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002089 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002090 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002091 goto failed;
2092 }
2093
2094 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002095 struct mgmt_cp_pin_code_neg_reply ncp;
2096
2097 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002098
2099 BT_ERR("PIN code is not 16 bytes long");
2100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002101 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002102 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002103 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002104 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002105
2106 goto failed;
2107 }
2108
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002109 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002110 if (!cmd) {
2111 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002112 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002113 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002114
Johan Hedbergd8457692012-02-17 14:24:57 +02002115 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002116 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002117 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002118
2119 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2120 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002121 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002122
2123failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002124 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002125 return err;
2126}
2127
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002128static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2129 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002130{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002131 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002132
2133 BT_DBG("");
2134
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002135 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002136
2137 hdev->io_capability = cp->io_capability;
2138
2139 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002140 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002141
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002142 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002143
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002144 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2145 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002146}
2147
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002148static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002149{
2150 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002151 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002152
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002153 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002154 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2155 continue;
2156
Johan Hedberge9a416b2011-02-19 12:05:56 -03002157 if (cmd->user_data != conn)
2158 continue;
2159
2160 return cmd;
2161 }
2162
2163 return NULL;
2164}
2165
2166static void pairing_complete(struct pending_cmd *cmd, u8 status)
2167{
2168 struct mgmt_rp_pair_device rp;
2169 struct hci_conn *conn = cmd->user_data;
2170
Johan Hedbergba4e5642011-11-11 00:07:34 +02002171 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002172 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002173
Johan Hedbergaee9b212012-02-18 15:07:59 +02002174 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002175 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002176
2177 /* So we don't get further callbacks for this connection */
2178 conn->connect_cfm_cb = NULL;
2179 conn->security_cfm_cb = NULL;
2180 conn->disconn_cfm_cb = NULL;
2181
David Herrmann76a68ba2013-04-06 20:28:37 +02002182 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002183
Johan Hedberga664b5b2011-02-19 12:06:02 -03002184 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002185}
2186
2187static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2188{
2189 struct pending_cmd *cmd;
2190
2191 BT_DBG("status %u", status);
2192
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002193 cmd = find_pairing(conn);
2194 if (!cmd)
2195 BT_DBG("Unable to find a pending command");
2196 else
Johan Hedberge2113262012-02-18 15:20:03 +02002197 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002198}
2199
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302200static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2201{
2202 struct pending_cmd *cmd;
2203
2204 BT_DBG("status %u", status);
2205
2206 if (!status)
2207 return;
2208
2209 cmd = find_pairing(conn);
2210 if (!cmd)
2211 BT_DBG("Unable to find a pending command");
2212 else
2213 pairing_complete(cmd, mgmt_status(status));
2214}
2215
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002216static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002217 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002218{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002219 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002220 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002221 struct pending_cmd *cmd;
2222 u8 sec_level, auth_type;
2223 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002224 int err;
2225
2226 BT_DBG("");
2227
Szymon Jancf950a30e2013-01-18 12:48:07 +01002228 memset(&rp, 0, sizeof(rp));
2229 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2230 rp.addr.type = cp->addr.type;
2231
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002232 if (!bdaddr_type_is_valid(cp->addr.type))
2233 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2234 MGMT_STATUS_INVALID_PARAMS,
2235 &rp, sizeof(rp));
2236
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002237 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002238
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002239 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002240 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2241 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002242 goto unlock;
2243 }
2244
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002245 sec_level = BT_SECURITY_MEDIUM;
2246 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002247 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002248 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002249 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002250
Andre Guedes591f47f2012-04-24 21:02:49 -03002251 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002252 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2253 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002254 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002255 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2256 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002257
Ville Tervo30e76272011-02-22 16:10:53 -03002258 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002259 int status;
2260
2261 if (PTR_ERR(conn) == -EBUSY)
2262 status = MGMT_STATUS_BUSY;
2263 else
2264 status = MGMT_STATUS_CONNECT_FAILED;
2265
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002266 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002267 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002268 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002269 goto unlock;
2270 }
2271
2272 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002273 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002274 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002275 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002276 goto unlock;
2277 }
2278
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002279 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002280 if (!cmd) {
2281 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002282 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002283 goto unlock;
2284 }
2285
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002286 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002287 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002288 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302289 else
2290 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002291
Johan Hedberge9a416b2011-02-19 12:05:56 -03002292 conn->security_cfm_cb = pairing_complete_cb;
2293 conn->disconn_cfm_cb = pairing_complete_cb;
2294 conn->io_capability = cp->io_cap;
2295 cmd->user_data = conn;
2296
2297 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002298 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002299 pairing_complete(cmd, 0);
2300
2301 err = 0;
2302
2303unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002304 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305 return err;
2306}
2307
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002308static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2309 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002310{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002311 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002312 struct pending_cmd *cmd;
2313 struct hci_conn *conn;
2314 int err;
2315
2316 BT_DBG("");
2317
Johan Hedberg28424702012-02-02 04:02:29 +02002318 hci_dev_lock(hdev);
2319
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002320 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002323 goto unlock;
2324 }
2325
Johan Hedberg28424702012-02-02 04:02:29 +02002326 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2327 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002328 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002329 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002330 goto unlock;
2331 }
2332
2333 conn = cmd->user_data;
2334
2335 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002336 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002337 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002338 goto unlock;
2339 }
2340
2341 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2342
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002343 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002344 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002345unlock:
2346 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002347 return err;
2348}
2349
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002350static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002351 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002352 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002353{
Johan Hedberga5c29682011-02-19 12:05:57 -03002354 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002355 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002356 int err;
2357
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002358 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002359
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002360 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002361 err = cmd_complete(sk, hdev->id, mgmt_op,
2362 MGMT_STATUS_NOT_POWERED, addr,
2363 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002364 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002365 }
2366
Johan Hedberg1707c602013-03-15 17:07:15 -05002367 if (addr->type == BDADDR_BREDR)
2368 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002369 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002370 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002371
Johan Hedberg272d90d2012-02-09 15:26:12 +02002372 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002373 err = cmd_complete(sk, hdev->id, mgmt_op,
2374 MGMT_STATUS_NOT_CONNECTED, addr,
2375 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002376 goto done;
2377 }
2378
Johan Hedberg1707c602013-03-15 17:07:15 -05002379 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002380 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002381 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002382
Brian Gix5fe57d92011-12-21 16:12:13 -08002383 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002384 err = cmd_complete(sk, hdev->id, mgmt_op,
2385 MGMT_STATUS_SUCCESS, addr,
2386 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002387 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002388 err = cmd_complete(sk, hdev->id, mgmt_op,
2389 MGMT_STATUS_FAILED, addr,
2390 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002391
Brian Gix47c15e22011-11-16 13:53:14 -08002392 goto done;
2393 }
2394
Johan Hedberg1707c602013-03-15 17:07:15 -05002395 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002396 if (!cmd) {
2397 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002398 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002399 }
2400
Brian Gix0df4c182011-11-16 13:53:13 -08002401 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002402 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2403 struct hci_cp_user_passkey_reply cp;
2404
Johan Hedberg1707c602013-03-15 17:07:15 -05002405 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002406 cp.passkey = passkey;
2407 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2408 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002409 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2410 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002411
Johan Hedberga664b5b2011-02-19 12:06:02 -03002412 if (err < 0)
2413 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002414
Brian Gix0df4c182011-11-16 13:53:13 -08002415done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002416 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002417 return err;
2418}
2419
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302420static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2421 void *data, u16 len)
2422{
2423 struct mgmt_cp_pin_code_neg_reply *cp = data;
2424
2425 BT_DBG("");
2426
Johan Hedberg1707c602013-03-15 17:07:15 -05002427 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302428 MGMT_OP_PIN_CODE_NEG_REPLY,
2429 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2430}
2431
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002432static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2433 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002434{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002435 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002436
2437 BT_DBG("");
2438
2439 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002440 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002441 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002442
Johan Hedberg1707c602013-03-15 17:07:15 -05002443 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002444 MGMT_OP_USER_CONFIRM_REPLY,
2445 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002446}
2447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002448static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002449 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002450{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002451 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002452
2453 BT_DBG("");
2454
Johan Hedberg1707c602013-03-15 17:07:15 -05002455 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002456 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2457 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002458}
2459
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002460static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2461 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002462{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002463 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002464
2465 BT_DBG("");
2466
Johan Hedberg1707c602013-03-15 17:07:15 -05002467 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002468 MGMT_OP_USER_PASSKEY_REPLY,
2469 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002470}
2471
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002472static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002474{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002475 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002476
2477 BT_DBG("");
2478
Johan Hedberg1707c602013-03-15 17:07:15 -05002479 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2481 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002482}
2483
Johan Hedberg13928972013-03-15 17:07:00 -05002484static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002485{
Johan Hedberg13928972013-03-15 17:07:00 -05002486 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002487 struct hci_cp_write_local_name cp;
2488
Johan Hedberg13928972013-03-15 17:07:00 -05002489 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002490
Johan Hedberg890ea892013-03-15 17:06:52 -05002491 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002492}
2493
Johan Hedberg13928972013-03-15 17:07:00 -05002494static void set_name_complete(struct hci_dev *hdev, u8 status)
2495{
2496 struct mgmt_cp_set_local_name *cp;
2497 struct pending_cmd *cmd;
2498
2499 BT_DBG("status 0x%02x", status);
2500
2501 hci_dev_lock(hdev);
2502
2503 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2504 if (!cmd)
2505 goto unlock;
2506
2507 cp = cmd->param;
2508
2509 if (status)
2510 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2511 mgmt_status(status));
2512 else
2513 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2514 cp, sizeof(*cp));
2515
2516 mgmt_pending_remove(cmd);
2517
2518unlock:
2519 hci_dev_unlock(hdev);
2520}
2521
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002522static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002523 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002524{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002525 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002526 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002527 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002528 int err;
2529
2530 BT_DBG("");
2531
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002532 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002533
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002534 /* If the old values are the same as the new ones just return a
2535 * direct command complete event.
2536 */
2537 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2538 !memcmp(hdev->short_name, cp->short_name,
2539 sizeof(hdev->short_name))) {
2540 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2541 data, len);
2542 goto failed;
2543 }
2544
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002545 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002546
Johan Hedbergb5235a62012-02-21 14:32:24 +02002547 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002548 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002549
2550 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002551 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002552 if (err < 0)
2553 goto failed;
2554
2555 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002556 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002557
Johan Hedbergb5235a62012-02-21 14:32:24 +02002558 goto failed;
2559 }
2560
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002561 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002562 if (!cmd) {
2563 err = -ENOMEM;
2564 goto failed;
2565 }
2566
Johan Hedberg13928972013-03-15 17:07:00 -05002567 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2568
Johan Hedberg890ea892013-03-15 17:06:52 -05002569 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002570
2571 if (lmp_bredr_capable(hdev)) {
2572 update_name(&req);
2573 update_eir(&req);
2574 }
2575
2576 if (lmp_le_capable(hdev))
2577 hci_update_ad(&req);
2578
Johan Hedberg13928972013-03-15 17:07:00 -05002579 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002580 if (err < 0)
2581 mgmt_pending_remove(cmd);
2582
2583failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002584 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002585 return err;
2586}
2587
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002588static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002589 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002590{
Szymon Jancc35938b2011-03-22 13:12:21 +01002591 struct pending_cmd *cmd;
2592 int err;
2593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002594 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002595
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002596 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002597
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002598 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002599 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002600 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002601 goto unlock;
2602 }
2603
Andre Guedes9a1a1992012-07-24 15:03:48 -03002604 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002605 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002606 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002607 goto unlock;
2608 }
2609
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002610 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002611 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002612 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002613 goto unlock;
2614 }
2615
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002616 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002617 if (!cmd) {
2618 err = -ENOMEM;
2619 goto unlock;
2620 }
2621
2622 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2623 if (err < 0)
2624 mgmt_pending_remove(cmd);
2625
2626unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002627 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002628 return err;
2629}
2630
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002631static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002632 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002633{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002634 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002635 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002636 int err;
2637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002638 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002640 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002641
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002642 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002643 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002644 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002645 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002646 else
Szymon Janca6785be2012-12-13 15:11:21 +01002647 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002648
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002649 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002650 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002652 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002653 return err;
2654}
2655
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002656static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002657 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002658{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002659 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002660 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002661 int err;
2662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002663 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002665 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002666
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002667 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002668 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002669 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002670 else
Szymon Janca6785be2012-12-13 15:11:21 +01002671 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002673 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002674 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002675
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002676 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002677 return err;
2678}
2679
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002680static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2681{
2682 struct pending_cmd *cmd;
2683 u8 type;
2684 int err;
2685
2686 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2687
2688 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2689 if (!cmd)
2690 return -ENOENT;
2691
2692 type = hdev->discovery.type;
2693
2694 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2695 &type, sizeof(type));
2696 mgmt_pending_remove(cmd);
2697
2698 return err;
2699}
2700
Andre Guedes7c307722013-04-30 15:29:28 -03002701static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2702{
2703 BT_DBG("status %d", status);
2704
2705 if (status) {
2706 hci_dev_lock(hdev);
2707 mgmt_start_discovery_failed(hdev, status);
2708 hci_dev_unlock(hdev);
2709 return;
2710 }
2711
2712 hci_dev_lock(hdev);
2713 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2714 hci_dev_unlock(hdev);
2715
2716 switch (hdev->discovery.type) {
2717 case DISCOV_TYPE_LE:
2718 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002719 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002720 break;
2721
2722 case DISCOV_TYPE_INTERLEAVED:
2723 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002724 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002725 break;
2726
2727 case DISCOV_TYPE_BREDR:
2728 break;
2729
2730 default:
2731 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2732 }
2733}
2734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002735static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002736 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002737{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002738 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002739 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002740 struct hci_cp_le_set_scan_param param_cp;
2741 struct hci_cp_le_set_scan_enable enable_cp;
2742 struct hci_cp_inquiry inq_cp;
2743 struct hci_request req;
2744 /* General inquiry access code (GIAC) */
2745 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002746 int err;
2747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002748 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002749
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002750 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002751
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002752 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002753 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002755 goto failed;
2756 }
2757
Andre Guedes642be6c2012-03-21 00:03:37 -03002758 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2759 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2760 MGMT_STATUS_BUSY);
2761 goto failed;
2762 }
2763
Johan Hedbergff9ef572012-01-04 14:23:45 +02002764 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002765 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002766 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002767 goto failed;
2768 }
2769
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002770 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002771 if (!cmd) {
2772 err = -ENOMEM;
2773 goto failed;
2774 }
2775
Andre Guedes4aab14e2012-02-17 20:39:36 -03002776 hdev->discovery.type = cp->type;
2777
Andre Guedes7c307722013-04-30 15:29:28 -03002778 hci_req_init(&req, hdev);
2779
Andre Guedes4aab14e2012-02-17 20:39:36 -03002780 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002781 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002782 if (!lmp_bredr_capable(hdev)) {
2783 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2784 MGMT_STATUS_NOT_SUPPORTED);
2785 mgmt_pending_remove(cmd);
2786 goto failed;
2787 }
2788
Andre Guedes7c307722013-04-30 15:29:28 -03002789 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2790 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2791 MGMT_STATUS_BUSY);
2792 mgmt_pending_remove(cmd);
2793 goto failed;
2794 }
2795
2796 hci_inquiry_cache_flush(hdev);
2797
2798 memset(&inq_cp, 0, sizeof(inq_cp));
2799 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002800 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002801 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002802 break;
2803
2804 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002805 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002806 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002807 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2808 MGMT_STATUS_NOT_SUPPORTED);
2809 mgmt_pending_remove(cmd);
2810 goto failed;
2811 }
2812
Andre Guedes7c307722013-04-30 15:29:28 -03002813 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
2814 !lmp_bredr_capable(hdev)) {
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_LE_PERIPHERAL, &hdev->dev_flags)) {
2822 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2823 MGMT_STATUS_REJECTED);
2824 mgmt_pending_remove(cmd);
2825 goto failed;
2826 }
2827
2828 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2829 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2830 MGMT_STATUS_BUSY);
2831 mgmt_pending_remove(cmd);
2832 goto failed;
2833 }
2834
2835 memset(&param_cp, 0, sizeof(param_cp));
2836 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002837 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2838 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002839 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2840 &param_cp);
2841
2842 memset(&enable_cp, 0, sizeof(enable_cp));
2843 enable_cp.enable = LE_SCAN_ENABLE;
2844 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2845 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2846 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002847 break;
2848
Andre Guedesf39799f2012-02-17 20:39:35 -03002849 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002850 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2851 MGMT_STATUS_INVALID_PARAMS);
2852 mgmt_pending_remove(cmd);
2853 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002854 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002855
Andre Guedes7c307722013-04-30 15:29:28 -03002856 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002857 if (err < 0)
2858 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002859 else
2860 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002861
2862failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002863 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002864 return err;
2865}
2866
Andre Guedes1183fdc2013-04-30 15:29:35 -03002867static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2868{
2869 struct pending_cmd *cmd;
2870 int err;
2871
2872 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2873 if (!cmd)
2874 return -ENOENT;
2875
2876 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2877 &hdev->discovery.type, sizeof(hdev->discovery.type));
2878 mgmt_pending_remove(cmd);
2879
2880 return err;
2881}
2882
Andre Guedes0e05bba2013-04-30 15:29:33 -03002883static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2884{
2885 BT_DBG("status %d", status);
2886
2887 hci_dev_lock(hdev);
2888
2889 if (status) {
2890 mgmt_stop_discovery_failed(hdev, status);
2891 goto unlock;
2892 }
2893
2894 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2895
2896unlock:
2897 hci_dev_unlock(hdev);
2898}
2899
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002900static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002901 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002902{
Johan Hedbergd9306502012-02-20 23:25:18 +02002903 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002904 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002905 struct hci_cp_remote_name_req_cancel cp;
2906 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002907 struct hci_request req;
2908 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002909 int err;
2910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002911 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002912
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002913 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002914
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002915 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002916 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2918 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002919 goto unlock;
2920 }
2921
2922 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002923 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002924 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2925 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002926 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002927 }
2928
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002929 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002930 if (!cmd) {
2931 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002932 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002933 }
2934
Andre Guedes0e05bba2013-04-30 15:29:33 -03002935 hci_req_init(&req, hdev);
2936
Andre Guedese0d9727e2012-03-20 15:15:36 -03002937 switch (hdev->discovery.state) {
2938 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002939 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2940 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2941 } else {
2942 cancel_delayed_work(&hdev->le_scan_disable);
2943
2944 memset(&enable_cp, 0, sizeof(enable_cp));
2945 enable_cp.enable = LE_SCAN_DISABLE;
2946 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2947 sizeof(enable_cp), &enable_cp);
2948 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002949
Andre Guedese0d9727e2012-03-20 15:15:36 -03002950 break;
2951
2952 case DISCOVERY_RESOLVING:
2953 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002954 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002955 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002956 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002957 err = cmd_complete(sk, hdev->id,
2958 MGMT_OP_STOP_DISCOVERY, 0,
2959 &mgmt_cp->type,
2960 sizeof(mgmt_cp->type));
2961 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2962 goto unlock;
2963 }
2964
2965 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002966 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2967 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002968
2969 break;
2970
2971 default:
2972 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002973
2974 mgmt_pending_remove(cmd);
2975 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
2976 MGMT_STATUS_FAILED, &mgmt_cp->type,
2977 sizeof(mgmt_cp->type));
2978 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002979 }
2980
Andre Guedes0e05bba2013-04-30 15:29:33 -03002981 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002982 if (err < 0)
2983 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002984 else
2985 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002986
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002987unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002988 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002989 return err;
2990}
2991
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002992static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002993 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002994{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002995 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002996 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002997 int err;
2998
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002999 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003000
Johan Hedberg561aafb2012-01-04 13:31:59 +02003001 hci_dev_lock(hdev);
3002
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003003 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003004 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003006 goto failed;
3007 }
3008
Johan Hedberga198e7b2012-02-17 14:27:06 +02003009 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003010 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003011 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003012 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003013 goto failed;
3014 }
3015
3016 if (cp->name_known) {
3017 e->name_state = NAME_KNOWN;
3018 list_del(&e->list);
3019 } else {
3020 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003021 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003022 }
3023
Johan Hedberge3846622013-01-09 15:29:33 +02003024 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3025 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003026
3027failed:
3028 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003029 return err;
3030}
3031
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003032static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003033 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003034{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003035 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003036 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003037 int err;
3038
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003039 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003040
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003041 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003042 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3043 MGMT_STATUS_INVALID_PARAMS,
3044 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003045
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003046 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003047
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003048 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003049 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003050 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003051 else
Szymon Janca6785be2012-12-13 15:11:21 +01003052 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003054 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003055 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003056
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003057 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003058
3059 return err;
3060}
3061
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003062static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003063 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003064{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003065 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003066 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003067 int err;
3068
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003069 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003070
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003071 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003072 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3073 MGMT_STATUS_INVALID_PARAMS,
3074 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003075
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003076 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003077
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003078 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003079 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003080 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003081 else
Szymon Janca6785be2012-12-13 15:11:21 +01003082 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003084 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003085 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003086
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003087 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003088
3089 return err;
3090}
3091
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003092static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3093 u16 len)
3094{
3095 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003096 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003097 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003098 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003099
3100 BT_DBG("%s", hdev->name);
3101
Szymon Jancc72d4b82012-03-16 16:02:57 +01003102 source = __le16_to_cpu(cp->source);
3103
3104 if (source > 0x0002)
3105 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3106 MGMT_STATUS_INVALID_PARAMS);
3107
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003108 hci_dev_lock(hdev);
3109
Szymon Jancc72d4b82012-03-16 16:02:57 +01003110 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003111 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3112 hdev->devid_product = __le16_to_cpu(cp->product);
3113 hdev->devid_version = __le16_to_cpu(cp->version);
3114
3115 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3116
Johan Hedberg890ea892013-03-15 17:06:52 -05003117 hci_req_init(&req, hdev);
3118 update_eir(&req);
3119 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003120
3121 hci_dev_unlock(hdev);
3122
3123 return err;
3124}
3125
Johan Hedberg33e38b32013-03-15 17:07:05 -05003126static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3127{
3128 struct pending_cmd *cmd;
3129
3130 BT_DBG("status 0x%02x", status);
3131
3132 hci_dev_lock(hdev);
3133
3134 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3135 if (!cmd)
3136 goto unlock;
3137
3138 if (status) {
3139 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3140 mgmt_status(status));
3141 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003142 struct mgmt_mode *cp = cmd->param;
3143
3144 if (cp->val)
3145 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3146 else
3147 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3148
Johan Hedberg33e38b32013-03-15 17:07:05 -05003149 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3150 new_settings(hdev, cmd->sk);
3151 }
3152
3153 mgmt_pending_remove(cmd);
3154
3155unlock:
3156 hci_dev_unlock(hdev);
3157}
3158
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003159static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003160 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003161{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003162 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003163 struct pending_cmd *cmd;
3164 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003165 int err;
3166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003167 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003168
Johan Hedberg1a47aee2013-03-15 17:07:06 -05003169 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003170 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3171 MGMT_STATUS_NOT_SUPPORTED);
3172
Johan Hedberga7e80f22013-01-09 16:05:19 +02003173 if (cp->val != 0x00 && cp->val != 0x01)
3174 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3175 MGMT_STATUS_INVALID_PARAMS);
3176
Johan Hedberg5400c042012-02-21 16:40:33 +02003177 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003178 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003179 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003180
3181 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003182 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003183 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003184
3185 hci_dev_lock(hdev);
3186
Johan Hedberg05cbf292013-03-15 17:07:07 -05003187 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3188 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3189 MGMT_STATUS_BUSY);
3190 goto unlock;
3191 }
3192
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003193 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3194 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3195 hdev);
3196 goto unlock;
3197 }
3198
Johan Hedberg33e38b32013-03-15 17:07:05 -05003199 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3200 data, len);
3201 if (!cmd) {
3202 err = -ENOMEM;
3203 goto unlock;
3204 }
3205
3206 hci_req_init(&req, hdev);
3207
Johan Hedberg406d7802013-03-15 17:07:09 -05003208 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003209
3210 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003211 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003212 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003213 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003214 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003215 }
3216
Johan Hedberg33e38b32013-03-15 17:07:05 -05003217unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003218 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003219
Antti Julkuf6422ec2011-06-22 13:11:56 +03003220 return err;
3221}
3222
Johan Hedberg3f706b72013-01-20 14:27:16 +02003223static bool ltk_is_valid(struct mgmt_ltk_info *key)
3224{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003225 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3226 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003227 if (key->master != 0x00 && key->master != 0x01)
3228 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003229 if (!bdaddr_type_is_le(key->addr.type))
3230 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003231 return true;
3232}
3233
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003234static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003235 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003236{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003237 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3238 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003239 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003240
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003241 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003242
3243 expected_len = sizeof(*cp) + key_count *
3244 sizeof(struct mgmt_ltk_info);
3245 if (expected_len != len) {
3246 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003247 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003248 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003249 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003250 }
3251
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003252 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003253
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003254 for (i = 0; i < key_count; i++) {
3255 struct mgmt_ltk_info *key = &cp->keys[i];
3256
Johan Hedberg3f706b72013-01-20 14:27:16 +02003257 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003258 return cmd_status(sk, hdev->id,
3259 MGMT_OP_LOAD_LONG_TERM_KEYS,
3260 MGMT_STATUS_INVALID_PARAMS);
3261 }
3262
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003263 hci_dev_lock(hdev);
3264
3265 hci_smp_ltks_clear(hdev);
3266
3267 for (i = 0; i < key_count; i++) {
3268 struct mgmt_ltk_info *key = &cp->keys[i];
3269 u8 type;
3270
3271 if (key->master)
3272 type = HCI_SMP_LTK;
3273 else
3274 type = HCI_SMP_LTK_SLAVE;
3275
Hemant Gupta4596fde2012-04-16 14:57:40 +05303276 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003277 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003278 type, 0, key->authenticated, key->val,
3279 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003280 }
3281
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003282 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3283 NULL, 0);
3284
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003285 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003286
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003287 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003288}
3289
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003290static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003291 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3292 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003293 bool var_len;
3294 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003295} mgmt_handlers[] = {
3296 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003297 { read_version, false, MGMT_READ_VERSION_SIZE },
3298 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3299 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3300 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3301 { set_powered, false, MGMT_SETTING_SIZE },
3302 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3303 { set_connectable, false, MGMT_SETTING_SIZE },
3304 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3305 { set_pairable, false, MGMT_SETTING_SIZE },
3306 { set_link_security, false, MGMT_SETTING_SIZE },
3307 { set_ssp, false, MGMT_SETTING_SIZE },
3308 { set_hs, false, MGMT_SETTING_SIZE },
3309 { set_le, false, MGMT_SETTING_SIZE },
3310 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3311 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3312 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3313 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3314 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3315 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3316 { disconnect, false, MGMT_DISCONNECT_SIZE },
3317 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3318 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3319 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3320 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3321 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3322 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3323 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3324 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3325 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3326 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3327 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3328 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3329 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3330 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3331 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3332 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3333 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3334 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3335 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003336 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003337};
3338
3339
Johan Hedberg03811012010-12-08 00:21:06 +02003340int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3341{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003342 void *buf;
3343 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003344 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003345 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003346 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003347 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003348 int err;
3349
3350 BT_DBG("got %zu bytes", msglen);
3351
3352 if (msglen < sizeof(*hdr))
3353 return -EINVAL;
3354
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003355 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003356 if (!buf)
3357 return -ENOMEM;
3358
3359 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3360 err = -EFAULT;
3361 goto done;
3362 }
3363
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003364 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003365 opcode = __le16_to_cpu(hdr->opcode);
3366 index = __le16_to_cpu(hdr->index);
3367 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003368
3369 if (len != msglen - sizeof(*hdr)) {
3370 err = -EINVAL;
3371 goto done;
3372 }
3373
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003374 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003375 hdev = hci_dev_get(index);
3376 if (!hdev) {
3377 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003378 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003379 goto done;
3380 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003381
3382 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3383 err = cmd_status(sk, index, opcode,
3384 MGMT_STATUS_INVALID_INDEX);
3385 goto done;
3386 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003387 }
3388
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003389 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003390 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003391 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003392 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003393 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003394 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003395 }
3396
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003397 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003398 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003399 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003400 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003401 goto done;
3402 }
3403
Johan Hedbergbe22b542012-03-01 22:24:41 +02003404 handler = &mgmt_handlers[opcode];
3405
3406 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003407 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003408 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003409 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003410 goto done;
3411 }
3412
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003413 if (hdev)
3414 mgmt_init_hdev(sk, hdev);
3415
3416 cp = buf + sizeof(*hdr);
3417
Johan Hedbergbe22b542012-03-01 22:24:41 +02003418 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003419 if (err < 0)
3420 goto done;
3421
Johan Hedberg03811012010-12-08 00:21:06 +02003422 err = msglen;
3423
3424done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003425 if (hdev)
3426 hci_dev_put(hdev);
3427
Johan Hedberg03811012010-12-08 00:21:06 +02003428 kfree(buf);
3429 return err;
3430}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003431
Johan Hedberg744cf192011-11-08 20:40:14 +02003432int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003433{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003434 if (!mgmt_valid_hdev(hdev))
3435 return -ENOTSUPP;
3436
Johan Hedberg744cf192011-11-08 20:40:14 +02003437 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003438}
3439
Johan Hedberg744cf192011-11-08 20:40:14 +02003440int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003441{
Johan Hedberg5f159032012-03-02 03:13:19 +02003442 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003443
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003444 if (!mgmt_valid_hdev(hdev))
3445 return -ENOTSUPP;
3446
Johan Hedberg744cf192011-11-08 20:40:14 +02003447 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003448
Johan Hedberg744cf192011-11-08 20:40:14 +02003449 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003450}
3451
Johan Hedberg890ea892013-03-15 17:06:52 -05003452static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003453{
Johan Hedberg890ea892013-03-15 17:06:52 -05003454 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003455 u8 scan = 0;
3456
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003457 /* Ensure that fast connectable is disabled. This function will
3458 * not do anything if the page scan parameters are already what
3459 * they should be.
3460 */
3461 write_fast_connectable(req, false);
3462
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003463 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3464 scan |= SCAN_PAGE;
3465 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3466 scan |= SCAN_INQUIRY;
3467
Johan Hedberg890ea892013-03-15 17:06:52 -05003468 if (scan)
3469 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003470}
3471
Johan Hedberg229ab392013-03-15 17:06:53 -05003472static void powered_complete(struct hci_dev *hdev, u8 status)
3473{
3474 struct cmd_lookup match = { NULL, hdev };
3475
3476 BT_DBG("status 0x%02x", status);
3477
3478 hci_dev_lock(hdev);
3479
3480 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3481
3482 new_settings(hdev, match.sk);
3483
3484 hci_dev_unlock(hdev);
3485
3486 if (match.sk)
3487 sock_put(match.sk);
3488}
3489
Johan Hedberg70da6242013-03-15 17:06:51 -05003490static int powered_update_hci(struct hci_dev *hdev)
3491{
Johan Hedberg890ea892013-03-15 17:06:52 -05003492 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003493 u8 link_sec;
3494
Johan Hedberg890ea892013-03-15 17:06:52 -05003495 hci_req_init(&req, hdev);
3496
Johan Hedberg70da6242013-03-15 17:06:51 -05003497 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3498 !lmp_host_ssp_capable(hdev)) {
3499 u8 ssp = 1;
3500
Johan Hedberg890ea892013-03-15 17:06:52 -05003501 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003502 }
3503
Johan Hedbergc73eee92013-04-19 18:35:21 +03003504 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3505 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003506 struct hci_cp_write_le_host_supported cp;
3507
3508 cp.le = 1;
3509 cp.simul = lmp_le_br_capable(hdev);
3510
3511 /* Check first if we already have the right
3512 * host state (host features set)
3513 */
3514 if (cp.le != lmp_host_le_capable(hdev) ||
3515 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003516 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3517 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003518 }
3519
3520 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3521 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003522 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3523 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003524
3525 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003526 set_bredr_scan(&req);
3527 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003528 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003529 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003530 }
3531
Johan Hedberg229ab392013-03-15 17:06:53 -05003532 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003533}
3534
Johan Hedberg744cf192011-11-08 20:40:14 +02003535int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003536{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003537 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003538 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3539 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003540 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003541
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003542 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3543 return 0;
3544
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003545 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003546 if (powered_update_hci(hdev) == 0)
3547 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003548
Johan Hedberg229ab392013-03-15 17:06:53 -05003549 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3550 &match);
3551 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003552 }
3553
Johan Hedberg229ab392013-03-15 17:06:53 -05003554 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3555 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3556
3557 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3558 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3559 zero_cod, sizeof(zero_cod), NULL);
3560
3561new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003562 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003563
3564 if (match.sk)
3565 sock_put(match.sk);
3566
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003567 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003568}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003569
Johan Hedberg96570ff2013-05-29 09:51:29 +03003570int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3571{
3572 struct pending_cmd *cmd;
3573 u8 status;
3574
3575 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3576 if (!cmd)
3577 return -ENOENT;
3578
3579 if (err == -ERFKILL)
3580 status = MGMT_STATUS_RFKILLED;
3581 else
3582 status = MGMT_STATUS_FAILED;
3583
3584 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3585
3586 mgmt_pending_remove(cmd);
3587
3588 return err;
3589}
3590
Johan Hedberg744cf192011-11-08 20:40:14 +02003591int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003592{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003593 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003594 bool changed = false;
3595 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003596
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003597 if (discoverable) {
3598 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3599 changed = true;
3600 } else {
3601 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3602 changed = true;
3603 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003604
Johan Hedberged9b5f22012-02-21 20:47:06 +02003605 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003606 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003607
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003608 if (changed)
3609 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003610
Johan Hedberg73f22f62010-12-29 16:00:25 +02003611 if (match.sk)
3612 sock_put(match.sk);
3613
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003614 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003615}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003616
Johan Hedberg744cf192011-11-08 20:40:14 +02003617int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003618{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003619 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003620 bool changed = false;
3621 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003622
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003623 if (connectable) {
3624 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3625 changed = true;
3626 } else {
3627 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3628 changed = true;
3629 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003630
Johan Hedberg2b76f452013-03-15 17:07:04 -05003631 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003632
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003633 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003634 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003635
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003636 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003637}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003638
Johan Hedberg744cf192011-11-08 20:40:14 +02003639int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003640{
Johan Hedbergca69b792011-11-11 18:10:00 +02003641 u8 mgmt_err = mgmt_status(status);
3642
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003643 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003644 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003645 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003646
3647 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003648 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003649 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003650
3651 return 0;
3652}
3653
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003654int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3655 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003656{
Johan Hedberg86742e12011-11-07 23:13:38 +02003657 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003658
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003659 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003660
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003661 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003662 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003663 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003664 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003665 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003666 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003667
Johan Hedberg744cf192011-11-08 20:40:14 +02003668 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003669}
Johan Hedbergf7520542011-01-20 12:34:39 +02003670
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003671int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3672{
3673 struct mgmt_ev_new_long_term_key ev;
3674
3675 memset(&ev, 0, sizeof(ev));
3676
3677 ev.store_hint = persistent;
3678 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003679 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003680 ev.key.authenticated = key->authenticated;
3681 ev.key.enc_size = key->enc_size;
3682 ev.key.ediv = key->ediv;
3683
3684 if (key->type == HCI_SMP_LTK)
3685 ev.key.master = 1;
3686
3687 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3688 memcpy(ev.key.val, key->val, sizeof(key->val));
3689
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003690 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3691 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003692}
3693
Johan Hedbergafc747a2012-01-15 18:11:07 +02003694int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003695 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3696 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003697{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003698 char buf[512];
3699 struct mgmt_ev_device_connected *ev = (void *) buf;
3700 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003701
Johan Hedbergb644ba32012-01-17 21:48:47 +02003702 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003703 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003704
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003705 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003706
Johan Hedbergb644ba32012-01-17 21:48:47 +02003707 if (name_len > 0)
3708 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003709 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003710
3711 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003712 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003713 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003714
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003715 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003716
3717 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003718 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003719}
3720
Johan Hedberg8962ee72011-01-20 12:40:27 +02003721static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3722{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003723 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003724 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003725 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003726
Johan Hedberg88c3df12012-02-09 14:27:38 +02003727 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3728 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003729
Johan Hedbergaee9b212012-02-18 15:07:59 +02003730 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003731 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003732
3733 *sk = cmd->sk;
3734 sock_hold(*sk);
3735
Johan Hedberga664b5b2011-02-19 12:06:02 -03003736 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003737}
3738
Johan Hedberg124f6e32012-02-09 13:50:12 +02003739static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003740{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003741 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003742 struct mgmt_cp_unpair_device *cp = cmd->param;
3743 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003744
3745 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003746 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3747 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003748
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003749 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3750
Johan Hedbergaee9b212012-02-18 15:07:59 +02003751 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003752
3753 mgmt_pending_remove(cmd);
3754}
3755
Johan Hedbergafc747a2012-01-15 18:11:07 +02003756int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003757 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003758{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003759 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003760 struct sock *sk = NULL;
3761 int err;
3762
Johan Hedberg744cf192011-11-08 20:40:14 +02003763 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003764
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003765 bacpy(&ev.addr.bdaddr, bdaddr);
3766 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3767 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003768
Johan Hedbergafc747a2012-01-15 18:11:07 +02003769 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003770 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003771
3772 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003773 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003774
Johan Hedberg124f6e32012-02-09 13:50:12 +02003775 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003776 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003777
Johan Hedberg8962ee72011-01-20 12:40:27 +02003778 return err;
3779}
3780
Johan Hedberg88c3df12012-02-09 14:27:38 +02003781int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003782 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003783{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003784 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003785 struct pending_cmd *cmd;
3786 int err;
3787
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003788 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3789 hdev);
3790
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003791 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003792 if (!cmd)
3793 return -ENOENT;
3794
Johan Hedberg88c3df12012-02-09 14:27:38 +02003795 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003796 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003797
Johan Hedberg88c3df12012-02-09 14:27:38 +02003798 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003799 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003800
Johan Hedberga664b5b2011-02-19 12:06:02 -03003801 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003802
3803 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003804}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003805
Johan Hedberg48264f02011-11-09 13:58:58 +02003806int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003807 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003808{
3809 struct mgmt_ev_connect_failed ev;
3810
Johan Hedberg4c659c32011-11-07 23:13:39 +02003811 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003812 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003813 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003814
Johan Hedberg744cf192011-11-08 20:40:14 +02003815 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003816}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003817
Johan Hedberg744cf192011-11-08 20:40:14 +02003818int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003819{
3820 struct mgmt_ev_pin_code_request ev;
3821
Johan Hedbergd8457692012-02-17 14:24:57 +02003822 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003823 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003824 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003825
Johan Hedberg744cf192011-11-08 20:40:14 +02003826 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003827 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003828}
3829
Johan Hedberg744cf192011-11-08 20:40:14 +02003830int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003831 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003832{
3833 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003834 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003835 int err;
3836
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003837 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003838 if (!cmd)
3839 return -ENOENT;
3840
Johan Hedbergd8457692012-02-17 14:24:57 +02003841 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003842 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003843
Johan Hedbergaee9b212012-02-18 15:07:59 +02003844 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003845 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003846
Johan Hedberga664b5b2011-02-19 12:06:02 -03003847 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003848
3849 return err;
3850}
3851
Johan Hedberg744cf192011-11-08 20:40:14 +02003852int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003853 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003854{
3855 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003856 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003857 int err;
3858
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003859 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003860 if (!cmd)
3861 return -ENOENT;
3862
Johan Hedbergd8457692012-02-17 14:24:57 +02003863 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003864 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003865
Johan Hedbergaee9b212012-02-18 15:07:59 +02003866 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003867 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003868
Johan Hedberga664b5b2011-02-19 12:06:02 -03003869 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003870
3871 return err;
3872}
Johan Hedberga5c29682011-02-19 12:05:57 -03003873
Johan Hedberg744cf192011-11-08 20:40:14 +02003874int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003875 u8 link_type, u8 addr_type, __le32 value,
3876 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003877{
3878 struct mgmt_ev_user_confirm_request ev;
3879
Johan Hedberg744cf192011-11-08 20:40:14 +02003880 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003881
Johan Hedberg272d90d2012-02-09 15:26:12 +02003882 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003883 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003884 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003885 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003886
Johan Hedberg744cf192011-11-08 20:40:14 +02003887 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003888 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003889}
3890
Johan Hedberg272d90d2012-02-09 15:26:12 +02003891int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003892 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003893{
3894 struct mgmt_ev_user_passkey_request ev;
3895
3896 BT_DBG("%s", hdev->name);
3897
Johan Hedberg272d90d2012-02-09 15:26:12 +02003898 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003899 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003900
3901 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003902 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003903}
3904
Brian Gix0df4c182011-11-16 13:53:13 -08003905static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003906 u8 link_type, u8 addr_type, u8 status,
3907 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003908{
3909 struct pending_cmd *cmd;
3910 struct mgmt_rp_user_confirm_reply rp;
3911 int err;
3912
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003913 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003914 if (!cmd)
3915 return -ENOENT;
3916
Johan Hedberg272d90d2012-02-09 15:26:12 +02003917 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003918 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003919 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003920 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003921
Johan Hedberga664b5b2011-02-19 12:06:02 -03003922 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003923
3924 return err;
3925}
3926
Johan Hedberg744cf192011-11-08 20:40:14 +02003927int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003928 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003929{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003930 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003931 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003932}
3933
Johan Hedberg272d90d2012-02-09 15:26:12 +02003934int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003935 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003936{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003937 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003938 status,
3939 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003940}
Johan Hedberg2a611692011-02-19 12:06:00 -03003941
Brian Gix604086b2011-11-23 08:28:33 -08003942int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003943 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003944{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003945 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003946 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003947}
3948
Johan Hedberg272d90d2012-02-09 15:26:12 +02003949int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003950 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003951{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003952 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003953 status,
3954 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003955}
3956
Johan Hedberg92a25252012-09-06 18:39:26 +03003957int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3958 u8 link_type, u8 addr_type, u32 passkey,
3959 u8 entered)
3960{
3961 struct mgmt_ev_passkey_notify ev;
3962
3963 BT_DBG("%s", hdev->name);
3964
3965 bacpy(&ev.addr.bdaddr, bdaddr);
3966 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3967 ev.passkey = __cpu_to_le32(passkey);
3968 ev.entered = entered;
3969
3970 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3971}
3972
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003973int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003974 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003975{
3976 struct mgmt_ev_auth_failed ev;
3977
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003978 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003979 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003980 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003981
Johan Hedberg744cf192011-11-08 20:40:14 +02003982 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003983}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003984
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003985int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3986{
3987 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003988 bool changed = false;
3989 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003990
3991 if (status) {
3992 u8 mgmt_err = mgmt_status(status);
3993 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003994 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003995 return 0;
3996 }
3997
Johan Hedberg47990ea2012-02-22 11:58:37 +02003998 if (test_bit(HCI_AUTH, &hdev->flags)) {
3999 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4000 changed = true;
4001 } else {
4002 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4003 changed = true;
4004 }
4005
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004006 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004007 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004008
Johan Hedberg47990ea2012-02-22 11:58:37 +02004009 if (changed)
4010 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004011
4012 if (match.sk)
4013 sock_put(match.sk);
4014
4015 return err;
4016}
4017
Johan Hedberg890ea892013-03-15 17:06:52 -05004018static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004019{
Johan Hedberg890ea892013-03-15 17:06:52 -05004020 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004021 struct hci_cp_write_eir cp;
4022
Johan Hedberg976eb202012-10-24 21:12:01 +03004023 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004024 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004025
Johan Hedbergc80da272012-02-22 15:38:48 +02004026 memset(hdev->eir, 0, sizeof(hdev->eir));
4027
Johan Hedbergcacaf522012-02-21 00:52:42 +02004028 memset(&cp, 0, sizeof(cp));
4029
Johan Hedberg890ea892013-03-15 17:06:52 -05004030 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004031}
4032
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004033int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004034{
4035 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004036 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004037 bool changed = false;
4038 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004039
4040 if (status) {
4041 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004042
4043 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004044 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004045 err = new_settings(hdev, NULL);
4046
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004047 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4048 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004049
4050 return err;
4051 }
4052
4053 if (enable) {
4054 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4055 changed = true;
4056 } else {
4057 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4058 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004059 }
4060
4061 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4062
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004063 if (changed)
4064 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004065
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004066 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004067 sock_put(match.sk);
4068
Johan Hedberg890ea892013-03-15 17:06:52 -05004069 hci_req_init(&req, hdev);
4070
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004071 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004072 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004073 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004074 clear_eir(&req);
4075
4076 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004077
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004078 return err;
4079}
4080
Johan Hedberg92da6092013-03-15 17:06:55 -05004081static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004082{
4083 struct cmd_lookup *match = data;
4084
Johan Hedberg90e70452012-02-23 23:09:40 +02004085 if (match->sk == NULL) {
4086 match->sk = cmd->sk;
4087 sock_hold(match->sk);
4088 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004089}
4090
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004091int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004092 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004093{
Johan Hedberg90e70452012-02-23 23:09:40 +02004094 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4095 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004096
Johan Hedberg92da6092013-03-15 17:06:55 -05004097 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4098 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4099 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004100
4101 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004102 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4103 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004104
4105 if (match.sk)
4106 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004107
4108 return err;
4109}
4110
Johan Hedberg744cf192011-11-08 20:40:14 +02004111int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004112{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004113 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004114 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004115
Johan Hedberg13928972013-03-15 17:07:00 -05004116 if (status)
4117 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004118
4119 memset(&ev, 0, sizeof(ev));
4120 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004121 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004122
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004123 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004124 if (!cmd) {
4125 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004126
Johan Hedberg13928972013-03-15 17:07:00 -05004127 /* If this is a HCI command related to powering on the
4128 * HCI dev don't send any mgmt signals.
4129 */
4130 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4131 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004132 }
4133
Johan Hedberg13928972013-03-15 17:07:00 -05004134 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4135 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004136}
Szymon Jancc35938b2011-03-22 13:12:21 +01004137
Johan Hedberg744cf192011-11-08 20:40:14 +02004138int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004139 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004140{
4141 struct pending_cmd *cmd;
4142 int err;
4143
Johan Hedberg744cf192011-11-08 20:40:14 +02004144 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004145
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004146 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004147 if (!cmd)
4148 return -ENOENT;
4149
4150 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004151 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4152 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004153 } else {
4154 struct mgmt_rp_read_local_oob_data rp;
4155
4156 memcpy(rp.hash, hash, sizeof(rp.hash));
4157 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4158
Johan Hedberg744cf192011-11-08 20:40:14 +02004159 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004160 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4161 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004162 }
4163
4164 mgmt_pending_remove(cmd);
4165
4166 return err;
4167}
Johan Hedberge17acd42011-03-30 23:57:16 +03004168
Johan Hedberg48264f02011-11-09 13:58:58 +02004169int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004170 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4171 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004172{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004173 char buf[512];
4174 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004175 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004176
Andre Guedes12602d02013-04-30 15:29:40 -03004177 if (!hci_discovery_active(hdev))
4178 return -EPERM;
4179
Johan Hedberg1dc06092012-01-15 21:01:23 +02004180 /* Leave 5 bytes for a potential CoD field */
4181 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004182 return -EINVAL;
4183
Johan Hedberg1dc06092012-01-15 21:01:23 +02004184 memset(buf, 0, sizeof(buf));
4185
Johan Hedberge319d2e2012-01-15 19:51:59 +02004186 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004187 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004188 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004189 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304190 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004191 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304192 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004193
Johan Hedberg1dc06092012-01-15 21:01:23 +02004194 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004195 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004196
Johan Hedberg1dc06092012-01-15 21:01:23 +02004197 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4198 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004199 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004200
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004201 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004202 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004203
Johan Hedberge319d2e2012-01-15 19:51:59 +02004204 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004205}
Johan Hedberga88a9652011-03-30 13:18:12 +03004206
Johan Hedbergb644ba32012-01-17 21:48:47 +02004207int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004208 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004209{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004210 struct mgmt_ev_device_found *ev;
4211 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4212 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004213
Johan Hedbergb644ba32012-01-17 21:48:47 +02004214 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004215
Johan Hedbergb644ba32012-01-17 21:48:47 +02004216 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004217
Johan Hedbergb644ba32012-01-17 21:48:47 +02004218 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004219 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004220 ev->rssi = rssi;
4221
4222 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004223 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004224
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004225 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004226
Johan Hedberg053c7e02012-02-04 00:06:00 +02004227 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004228 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004229}
Johan Hedberg314b2382011-04-27 10:29:57 -04004230
Johan Hedberg744cf192011-11-08 20:40:14 +02004231int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004232{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004233 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004234 struct pending_cmd *cmd;
4235
Andre Guedes343fb142011-11-22 17:14:19 -03004236 BT_DBG("%s discovering %u", hdev->name, discovering);
4237
Johan Hedberg164a6e72011-11-01 17:06:44 +02004238 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004239 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004240 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004241 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004242
4243 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004244 u8 type = hdev->discovery.type;
4245
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004246 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4247 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004248 mgmt_pending_remove(cmd);
4249 }
4250
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004251 memset(&ev, 0, sizeof(ev));
4252 ev.type = hdev->discovery.type;
4253 ev.discovering = discovering;
4254
4255 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004256}
Antti Julku5e762442011-08-25 16:48:02 +03004257
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004258int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004259{
4260 struct pending_cmd *cmd;
4261 struct mgmt_ev_device_blocked ev;
4262
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004263 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004264
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004265 bacpy(&ev.addr.bdaddr, bdaddr);
4266 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004267
Johan Hedberg744cf192011-11-08 20:40:14 +02004268 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004269 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004270}
4271
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004272int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004273{
4274 struct pending_cmd *cmd;
4275 struct mgmt_ev_device_unblocked ev;
4276
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004277 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004278
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004279 bacpy(&ev.addr.bdaddr, bdaddr);
4280 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004281
Johan Hedberg744cf192011-11-08 20:40:14 +02004282 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004283 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004284}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01004285
4286module_param(enable_hs, bool, 0644);
4287MODULE_PARM_DESC(enable_hs, "Enable High Speed support");