blob: 9a2faa310b7c24ce0b66049c8f63f852e241286e [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
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300387 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200388 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300389 settings |= MGMT_SETTING_ADVERTISING;
390 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392 return settings;
393}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200394
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395static u32 get_current_settings(struct hci_dev *hdev)
396{
397 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200398
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200399 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100400 settings |= MGMT_SETTING_POWERED;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_CONNECTABLE;
404
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500405 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
406 settings |= MGMT_SETTING_FAST_CONNECTABLE;
407
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200408 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_DISCOVERABLE;
410
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200411 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_PAIRABLE;
413
Andre Guedesed3fa312012-07-24 15:03:46 -0300414 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_BREDR;
416
Johan Hedberg06199cf2012-02-22 16:37:11 +0200417 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg47990ea2012-02-22 11:58:37 +0200420 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200422
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200423 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200424 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200425
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200426 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
427 settings |= MGMT_SETTING_HS;
428
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300429 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
430 settings |= MGMT_SETTING_ADVERTISING;
431
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200432 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200433}
434
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300435#define PNP_INFO_SVCLASS_ID 0x1200
436
Johan Hedberg213202e2013-01-27 00:31:33 +0200437static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
438{
439 u8 *ptr = data, *uuids_start = NULL;
440 struct bt_uuid *uuid;
441
442 if (len < 4)
443 return ptr;
444
445 list_for_each_entry(uuid, &hdev->uuids, list) {
446 u16 uuid16;
447
448 if (uuid->size != 16)
449 continue;
450
451 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
452 if (uuid16 < 0x1100)
453 continue;
454
455 if (uuid16 == PNP_INFO_SVCLASS_ID)
456 continue;
457
458 if (!uuids_start) {
459 uuids_start = ptr;
460 uuids_start[0] = 1;
461 uuids_start[1] = EIR_UUID16_ALL;
462 ptr += 2;
463 }
464
465 /* Stop if not enough space to put next UUID */
466 if ((ptr - data) + sizeof(u16) > len) {
467 uuids_start[1] = EIR_UUID16_SOME;
468 break;
469 }
470
471 *ptr++ = (uuid16 & 0x00ff);
472 *ptr++ = (uuid16 & 0xff00) >> 8;
473 uuids_start[0] += sizeof(uuid16);
474 }
475
476 return ptr;
477}
478
Johan Hedbergcdf19632013-01-27 00:31:34 +0200479static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
480{
481 u8 *ptr = data, *uuids_start = NULL;
482 struct bt_uuid *uuid;
483
484 if (len < 6)
485 return ptr;
486
487 list_for_each_entry(uuid, &hdev->uuids, list) {
488 if (uuid->size != 32)
489 continue;
490
491 if (!uuids_start) {
492 uuids_start = ptr;
493 uuids_start[0] = 1;
494 uuids_start[1] = EIR_UUID32_ALL;
495 ptr += 2;
496 }
497
498 /* Stop if not enough space to put next UUID */
499 if ((ptr - data) + sizeof(u32) > len) {
500 uuids_start[1] = EIR_UUID32_SOME;
501 break;
502 }
503
504 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
505 ptr += sizeof(u32);
506 uuids_start[0] += sizeof(u32);
507 }
508
509 return ptr;
510}
511
Johan Hedbergc00d5752013-01-27 00:31:35 +0200512static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
513{
514 u8 *ptr = data, *uuids_start = NULL;
515 struct bt_uuid *uuid;
516
517 if (len < 18)
518 return ptr;
519
520 list_for_each_entry(uuid, &hdev->uuids, list) {
521 if (uuid->size != 128)
522 continue;
523
524 if (!uuids_start) {
525 uuids_start = ptr;
526 uuids_start[0] = 1;
527 uuids_start[1] = EIR_UUID128_ALL;
528 ptr += 2;
529 }
530
531 /* Stop if not enough space to put next UUID */
532 if ((ptr - data) + 16 > len) {
533 uuids_start[1] = EIR_UUID128_SOME;
534 break;
535 }
536
537 memcpy(ptr, uuid->uuid, 16);
538 ptr += 16;
539 uuids_start[0] += 16;
540 }
541
542 return ptr;
543}
544
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545static void create_eir(struct hci_dev *hdev, u8 *data)
546{
547 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300548 size_t name_len;
549
550 name_len = strlen(hdev->dev_name);
551
552 if (name_len > 0) {
553 /* EIR Data type */
554 if (name_len > 48) {
555 name_len = 48;
556 ptr[1] = EIR_NAME_SHORT;
557 } else
558 ptr[1] = EIR_NAME_COMPLETE;
559
560 /* EIR Data length */
561 ptr[0] = name_len + 1;
562
563 memcpy(ptr + 2, hdev->dev_name, name_len);
564
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300565 ptr += (name_len + 2);
566 }
567
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100568 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700569 ptr[0] = 2;
570 ptr[1] = EIR_TX_POWER;
571 ptr[2] = (u8) hdev->inq_tx_power;
572
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700573 ptr += 3;
574 }
575
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700576 if (hdev->devid_source > 0) {
577 ptr[0] = 9;
578 ptr[1] = EIR_DEVICE_ID;
579
580 put_unaligned_le16(hdev->devid_source, ptr + 2);
581 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
582 put_unaligned_le16(hdev->devid_product, ptr + 6);
583 put_unaligned_le16(hdev->devid_version, ptr + 8);
584
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700585 ptr += 10;
586 }
587
Johan Hedberg213202e2013-01-27 00:31:33 +0200588 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200589 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200590 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300591}
592
Johan Hedberg890ea892013-03-15 17:06:52 -0500593static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300594{
Johan Hedberg890ea892013-03-15 17:06:52 -0500595 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300596 struct hci_cp_write_eir cp;
597
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200598 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500599 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200600
Johan Hedberg976eb202012-10-24 21:12:01 +0300601 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500602 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300603
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200604 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500605 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300606
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200607 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500608 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300609
610 memset(&cp, 0, sizeof(cp));
611
612 create_eir(hdev, cp.data);
613
614 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500615 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300616
617 memcpy(hdev->eir, cp.data, sizeof(cp.data));
618
Johan Hedberg890ea892013-03-15 17:06:52 -0500619 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300620}
621
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200622static u8 get_service_classes(struct hci_dev *hdev)
623{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300624 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200625 u8 val = 0;
626
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300627 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200629
630 return val;
631}
632
Johan Hedberg890ea892013-03-15 17:06:52 -0500633static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200634{
Johan Hedberg890ea892013-03-15 17:06:52 -0500635 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200636 u8 cod[3];
637
638 BT_DBG("%s", hdev->name);
639
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200640 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500641 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200642
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200643 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500644 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200645
646 cod[0] = hdev->minor_class;
647 cod[1] = hdev->major_class;
648 cod[2] = get_service_classes(hdev);
649
650 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500651 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200652
Johan Hedberg890ea892013-03-15 17:06:52 -0500653 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200654}
655
Johan Hedberg7d785252011-12-15 00:47:39 +0200656static void service_cache_off(struct work_struct *work)
657{
658 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300659 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500660 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200661
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200662 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200663 return;
664
Johan Hedberg890ea892013-03-15 17:06:52 -0500665 hci_req_init(&req, hdev);
666
Johan Hedberg7d785252011-12-15 00:47:39 +0200667 hci_dev_lock(hdev);
668
Johan Hedberg890ea892013-03-15 17:06:52 -0500669 update_eir(&req);
670 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200671
672 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500673
674 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200675}
676
Johan Hedberg6a919082012-02-28 06:17:26 +0200677static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200678{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200679 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200680 return;
681
Johan Hedberg4f87da82012-03-02 19:55:56 +0200682 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200683
Johan Hedberg4f87da82012-03-02 19:55:56 +0200684 /* Non-mgmt controlled devices get this bit set
685 * implicitly so that pairing works for them, however
686 * for mgmt we require user-space to explicitly enable
687 * it
688 */
689 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200690}
691
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200692static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300693 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200694{
695 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200696
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200697 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200698
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300699 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200700
Johan Hedberg03811012010-12-08 00:21:06 +0200701 memset(&rp, 0, sizeof(rp));
702
Johan Hedberg03811012010-12-08 00:21:06 +0200703 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200704
705 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200706 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200707
708 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
709 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
710
711 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200712
713 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200714 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200715
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300716 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200717
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200718 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300719 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200720}
721
722static void mgmt_pending_free(struct pending_cmd *cmd)
723{
724 sock_put(cmd->sk);
725 kfree(cmd->param);
726 kfree(cmd);
727}
728
729static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300730 struct hci_dev *hdev, void *data,
731 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200732{
733 struct pending_cmd *cmd;
734
Andre Guedes12b94562012-06-07 19:05:45 -0300735 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200736 if (!cmd)
737 return NULL;
738
739 cmd->opcode = opcode;
740 cmd->index = hdev->id;
741
Andre Guedes12b94562012-06-07 19:05:45 -0300742 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200743 if (!cmd->param) {
744 kfree(cmd);
745 return NULL;
746 }
747
748 if (data)
749 memcpy(cmd->param, data, len);
750
751 cmd->sk = sk;
752 sock_hold(sk);
753
754 list_add(&cmd->list, &hdev->mgmt_pending);
755
756 return cmd;
757}
758
759static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300760 void (*cb)(struct pending_cmd *cmd,
761 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300762 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200763{
Andre Guedesa3d09352013-02-01 11:21:30 -0300764 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200765
Andre Guedesa3d09352013-02-01 11:21:30 -0300766 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200767 if (opcode > 0 && cmd->opcode != opcode)
768 continue;
769
770 cb(cmd, data);
771 }
772}
773
774static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
775{
776 struct pending_cmd *cmd;
777
778 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
779 if (cmd->opcode == opcode)
780 return cmd;
781 }
782
783 return NULL;
784}
785
786static void mgmt_pending_remove(struct pending_cmd *cmd)
787{
788 list_del(&cmd->list);
789 mgmt_pending_free(cmd);
790}
791
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200792static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200793{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200794 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200795
Johan Hedbergaee9b212012-02-18 15:07:59 +0200796 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300797 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200798}
799
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200800static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300801 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200802{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300803 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200804 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200805 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200806
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200807 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200808
Johan Hedberga7e80f22013-01-09 16:05:19 +0200809 if (cp->val != 0x00 && cp->val != 0x01)
810 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
811 MGMT_STATUS_INVALID_PARAMS);
812
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300813 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200814
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300815 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
816 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
817 MGMT_STATUS_BUSY);
818 goto failed;
819 }
820
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100821 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
822 cancel_delayed_work(&hdev->power_off);
823
824 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200825 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
826 data, len);
827 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100828 goto failed;
829 }
830 }
831
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200832 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200833 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200834 goto failed;
835 }
836
Johan Hedberg03811012010-12-08 00:21:06 +0200837 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
838 if (!cmd) {
839 err = -ENOMEM;
840 goto failed;
841 }
842
843 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200844 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200845 else
Johan Hedberg19202572013-01-14 22:33:51 +0200846 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200847
848 err = 0;
849
850failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300851 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200852 return err;
853}
854
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300855static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
856 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200857{
858 struct sk_buff *skb;
859 struct mgmt_hdr *hdr;
860
Andre Guedes790eff42012-06-07 19:05:46 -0300861 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200862 if (!skb)
863 return -ENOMEM;
864
865 hdr = (void *) skb_put(skb, sizeof(*hdr));
866 hdr->opcode = cpu_to_le16(event);
867 if (hdev)
868 hdr->index = cpu_to_le16(hdev->id);
869 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530870 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200871 hdr->len = cpu_to_le16(data_len);
872
873 if (data)
874 memcpy(skb_put(skb, data_len), data, data_len);
875
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100876 /* Time stamp */
877 __net_timestamp(skb);
878
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200879 hci_send_to_control(skb, skip_sk);
880 kfree_skb(skb);
881
882 return 0;
883}
884
885static int new_settings(struct hci_dev *hdev, struct sock *skip)
886{
887 __le32 ev;
888
889 ev = cpu_to_le32(get_current_settings(hdev));
890
891 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
892}
893
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300894struct cmd_lookup {
895 struct sock *sk;
896 struct hci_dev *hdev;
897 u8 mgmt_status;
898};
899
900static void settings_rsp(struct pending_cmd *cmd, void *data)
901{
902 struct cmd_lookup *match = data;
903
904 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
905
906 list_del(&cmd->list);
907
908 if (match->sk == NULL) {
909 match->sk = cmd->sk;
910 sock_hold(match->sk);
911 }
912
913 mgmt_pending_free(cmd);
914}
915
916static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
917{
918 u8 *status = data;
919
920 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
921 mgmt_pending_remove(cmd);
922}
923
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200924static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300925 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200926{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300927 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200928 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200929 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200930 u8 scan;
931 int err;
932
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200933 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200934
Johan Hedberg33c525c2012-10-24 21:11:58 +0300935 if (!lmp_bredr_capable(hdev))
936 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
937 MGMT_STATUS_NOT_SUPPORTED);
938
Johan Hedberga7e80f22013-01-09 16:05:19 +0200939 if (cp->val != 0x00 && cp->val != 0x01)
940 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
941 MGMT_STATUS_INVALID_PARAMS);
942
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700943 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100944 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300946 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200947
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300948 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200949
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200950 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200951 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300952 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200953 goto failed;
954 }
955
956 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300957 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200958 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300959 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200960 goto failed;
961 }
962
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200963 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200964 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300965 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200966 goto failed;
967 }
968
969 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200970 bool changed = false;
971
972 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
973 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
974 changed = true;
975 }
976
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200977 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200978 if (err < 0)
979 goto failed;
980
981 if (changed)
982 err = new_settings(hdev, sk);
983
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200984 goto failed;
985 }
986
987 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100988 if (hdev->discov_timeout > 0) {
989 cancel_delayed_work(&hdev->discov_off);
990 hdev->discov_timeout = 0;
991 }
992
993 if (cp->val && timeout > 0) {
994 hdev->discov_timeout = timeout;
995 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
996 msecs_to_jiffies(hdev->discov_timeout * 1000));
997 }
998
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200999 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001000 goto failed;
1001 }
1002
1003 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1004 if (!cmd) {
1005 err = -ENOMEM;
1006 goto failed;
1007 }
1008
1009 scan = SCAN_PAGE;
1010
1011 if (cp->val)
1012 scan |= SCAN_INQUIRY;
1013 else
1014 cancel_delayed_work(&hdev->discov_off);
1015
1016 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1017 if (err < 0)
1018 mgmt_pending_remove(cmd);
1019
Johan Hedberg03811012010-12-08 00:21:06 +02001020 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001021 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001022
1023failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001024 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001025 return err;
1026}
1027
Johan Hedberg406d7802013-03-15 17:07:09 -05001028static void write_fast_connectable(struct hci_request *req, bool enable)
1029{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001030 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001031 struct hci_cp_write_page_scan_activity acp;
1032 u8 type;
1033
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001034 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1035 return;
1036
Johan Hedberg406d7802013-03-15 17:07:09 -05001037 if (enable) {
1038 type = PAGE_SCAN_TYPE_INTERLACED;
1039
1040 /* 160 msec page scan interval */
1041 acp.interval = __constant_cpu_to_le16(0x0100);
1042 } else {
1043 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1044
1045 /* default 1.28 sec page scan */
1046 acp.interval = __constant_cpu_to_le16(0x0800);
1047 }
1048
1049 acp.window = __constant_cpu_to_le16(0x0012);
1050
Johan Hedbergbd98b992013-03-15 17:07:13 -05001051 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1052 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1053 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1054 sizeof(acp), &acp);
1055
1056 if (hdev->page_scan_type != type)
1057 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001058}
1059
Johan Hedberg2b76f452013-03-15 17:07:04 -05001060static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1061{
1062 struct pending_cmd *cmd;
1063
1064 BT_DBG("status 0x%02x", status);
1065
1066 hci_dev_lock(hdev);
1067
1068 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1069 if (!cmd)
1070 goto unlock;
1071
1072 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1073
1074 mgmt_pending_remove(cmd);
1075
1076unlock:
1077 hci_dev_unlock(hdev);
1078}
1079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001080static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001081 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001082{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001083 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001084 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001085 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001086 u8 scan;
1087 int err;
1088
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001089 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001090
Johan Hedberg33c525c2012-10-24 21:11:58 +03001091 if (!lmp_bredr_capable(hdev))
1092 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1093 MGMT_STATUS_NOT_SUPPORTED);
1094
Johan Hedberga7e80f22013-01-09 16:05:19 +02001095 if (cp->val != 0x00 && cp->val != 0x01)
1096 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1097 MGMT_STATUS_INVALID_PARAMS);
1098
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001099 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001100
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001101 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001102 bool changed = false;
1103
1104 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1105 changed = true;
1106
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001107 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001108 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001109 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001110 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1111 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1112 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001113
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001114 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001115 if (err < 0)
1116 goto failed;
1117
1118 if (changed)
1119 err = new_settings(hdev, sk);
1120
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001121 goto failed;
1122 }
1123
1124 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001125 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001126 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001127 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001128 goto failed;
1129 }
1130
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001131 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001132 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001133 goto failed;
1134 }
1135
1136 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1137 if (!cmd) {
1138 err = -ENOMEM;
1139 goto failed;
1140 }
1141
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001142 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001143 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001144 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001145 scan = 0;
1146
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001147 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001148 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001149 cancel_delayed_work(&hdev->discov_off);
1150 }
1151
Johan Hedberg2b76f452013-03-15 17:07:04 -05001152 hci_req_init(&req, hdev);
1153
1154 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1155
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001156 /* If we're going from non-connectable to connectable or
1157 * vice-versa when fast connectable is enabled ensure that fast
1158 * connectable gets disabled. write_fast_connectable won't do
1159 * anything if the page scan parameters are already what they
1160 * should be.
1161 */
1162 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001163 write_fast_connectable(&req, false);
1164
Johan Hedberg2b76f452013-03-15 17:07:04 -05001165 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166 if (err < 0)
1167 mgmt_pending_remove(cmd);
1168
1169failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001170 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001171 return err;
1172}
1173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001175 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001176{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001177 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001178 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001181
Johan Hedberga7e80f22013-01-09 16:05:19 +02001182 if (cp->val != 0x00 && cp->val != 0x01)
1183 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1184 MGMT_STATUS_INVALID_PARAMS);
1185
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001186 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187
1188 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001189 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001190 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001191 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001192
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001193 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001194 if (err < 0)
1195 goto failed;
1196
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001197 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001198
1199failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001200 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001201 return err;
1202}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001203
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001204static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1205 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001206{
1207 struct mgmt_mode *cp = data;
1208 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001209 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001210 int err;
1211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001212 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001213
Johan Hedberg33c525c2012-10-24 21:11:58 +03001214 if (!lmp_bredr_capable(hdev))
1215 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1216 MGMT_STATUS_NOT_SUPPORTED);
1217
Johan Hedberga7e80f22013-01-09 16:05:19 +02001218 if (cp->val != 0x00 && cp->val != 0x01)
1219 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1220 MGMT_STATUS_INVALID_PARAMS);
1221
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001222 hci_dev_lock(hdev);
1223
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001224 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001225 bool changed = false;
1226
1227 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001228 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001229 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1230 changed = true;
1231 }
1232
1233 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1234 if (err < 0)
1235 goto failed;
1236
1237 if (changed)
1238 err = new_settings(hdev, sk);
1239
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001240 goto failed;
1241 }
1242
1243 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001244 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001245 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001246 goto failed;
1247 }
1248
1249 val = !!cp->val;
1250
1251 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1252 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1253 goto failed;
1254 }
1255
1256 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1257 if (!cmd) {
1258 err = -ENOMEM;
1259 goto failed;
1260 }
1261
1262 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1263 if (err < 0) {
1264 mgmt_pending_remove(cmd);
1265 goto failed;
1266 }
1267
1268failed:
1269 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001270 return err;
1271}
1272
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001273static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001274{
1275 struct mgmt_mode *cp = data;
1276 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001277 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001278 int err;
1279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001280 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001281
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001282 if (!lmp_ssp_capable(hdev))
1283 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1284 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001285
Johan Hedberga7e80f22013-01-09 16:05:19 +02001286 if (cp->val != 0x00 && cp->val != 0x01)
1287 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1288 MGMT_STATUS_INVALID_PARAMS);
1289
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001290 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001291
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001292 val = !!cp->val;
1293
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001294 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001295 bool changed = false;
1296
1297 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1298 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1299 changed = true;
1300 }
1301
1302 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1303 if (err < 0)
1304 goto failed;
1305
1306 if (changed)
1307 err = new_settings(hdev, sk);
1308
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001309 goto failed;
1310 }
1311
1312 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001313 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1314 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001315 goto failed;
1316 }
1317
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001318 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1319 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1320 goto failed;
1321 }
1322
1323 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1324 if (!cmd) {
1325 err = -ENOMEM;
1326 goto failed;
1327 }
1328
1329 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1330 if (err < 0) {
1331 mgmt_pending_remove(cmd);
1332 goto failed;
1333 }
1334
1335failed:
1336 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001337 return err;
1338}
1339
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001340static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001341{
1342 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001343
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001344 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001345
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001346 if (!enable_hs)
1347 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001348 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001349
Johan Hedberga7e80f22013-01-09 16:05:19 +02001350 if (cp->val != 0x00 && cp->val != 0x01)
1351 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1352 MGMT_STATUS_INVALID_PARAMS);
1353
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001354 if (cp->val)
1355 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1356 else
1357 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1358
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001359 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001360}
1361
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001362static void le_enable_complete(struct hci_dev *hdev, u8 status)
1363{
1364 struct cmd_lookup match = { NULL, hdev };
1365
1366 if (status) {
1367 u8 mgmt_err = mgmt_status(status);
1368
1369 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1370 &mgmt_err);
1371 return;
1372 }
1373
1374 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1375
1376 new_settings(hdev, match.sk);
1377
1378 if (match.sk)
1379 sock_put(match.sk);
1380}
1381
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001382static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001383{
1384 struct mgmt_mode *cp = data;
1385 struct hci_cp_write_le_host_supported hci_cp;
1386 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001387 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001388 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001389 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001391 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001392
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001393 if (!lmp_le_capable(hdev))
1394 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1395 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001396
Johan Hedberga7e80f22013-01-09 16:05:19 +02001397 if (cp->val != 0x00 && cp->val != 0x01)
1398 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1399 MGMT_STATUS_INVALID_PARAMS);
1400
Johan Hedbergc73eee92013-04-19 18:35:21 +03001401 /* LE-only devices do not allow toggling LE on/off */
1402 if (!lmp_bredr_capable(hdev))
1403 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1404 MGMT_STATUS_REJECTED);
1405
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001406 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001407
1408 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001409 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001410
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001411 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001412 bool changed = false;
1413
1414 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1415 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1416 changed = true;
1417 }
1418
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001419 if (!val && test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
1420 clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
1421 changed = true;
1422 }
1423
Johan Hedberg06199cf2012-02-22 16:37:11 +02001424 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1425 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001426 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001427
1428 if (changed)
1429 err = new_settings(hdev, sk);
1430
Johan Hedberg1de028c2012-02-29 19:55:35 -08001431 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001432 }
1433
1434 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001435 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001436 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001437 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001438 }
1439
1440 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1441 if (!cmd) {
1442 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001443 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001444 }
1445
1446 memset(&hci_cp, 0, sizeof(hci_cp));
1447
1448 if (val) {
1449 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001450 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001451 }
1452
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001453 hci_req_init(&req, hdev);
1454
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001455 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags) && !val)
1456 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(val), &val);
1457
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001458 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1459 &hci_cp);
1460
1461 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301462 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001463 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001464
Johan Hedberg1de028c2012-02-29 19:55:35 -08001465unlock:
1466 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001467 return err;
1468}
1469
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001470/* This is a helper function to test for pending mgmt commands that can
1471 * cause CoD or EIR HCI commands. We can only allow one such pending
1472 * mgmt command at a time since otherwise we cannot easily track what
1473 * the current values are, will be, and based on that calculate if a new
1474 * HCI command needs to be sent and if yes with what value.
1475 */
1476static bool pending_eir_or_class(struct hci_dev *hdev)
1477{
1478 struct pending_cmd *cmd;
1479
1480 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1481 switch (cmd->opcode) {
1482 case MGMT_OP_ADD_UUID:
1483 case MGMT_OP_REMOVE_UUID:
1484 case MGMT_OP_SET_DEV_CLASS:
1485 case MGMT_OP_SET_POWERED:
1486 return true;
1487 }
1488 }
1489
1490 return false;
1491}
1492
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001493static const u8 bluetooth_base_uuid[] = {
1494 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1495 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1496};
1497
1498static u8 get_uuid_size(const u8 *uuid)
1499{
1500 u32 val;
1501
1502 if (memcmp(uuid, bluetooth_base_uuid, 12))
1503 return 128;
1504
1505 val = get_unaligned_le32(&uuid[12]);
1506 if (val > 0xffff)
1507 return 32;
1508
1509 return 16;
1510}
1511
Johan Hedberg92da6092013-03-15 17:06:55 -05001512static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1513{
1514 struct pending_cmd *cmd;
1515
1516 hci_dev_lock(hdev);
1517
1518 cmd = mgmt_pending_find(mgmt_op, hdev);
1519 if (!cmd)
1520 goto unlock;
1521
1522 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1523 hdev->dev_class, 3);
1524
1525 mgmt_pending_remove(cmd);
1526
1527unlock:
1528 hci_dev_unlock(hdev);
1529}
1530
1531static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1532{
1533 BT_DBG("status 0x%02x", status);
1534
1535 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1536}
1537
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001538static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001539{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001540 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001541 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001542 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001543 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001544 int err;
1545
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001546 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001547
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001548 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001549
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001550 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001551 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001552 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001553 goto failed;
1554 }
1555
Andre Guedes92c4c202012-06-07 19:05:44 -03001556 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001557 if (!uuid) {
1558 err = -ENOMEM;
1559 goto failed;
1560 }
1561
1562 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001563 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001564 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001565
Johan Hedbergde66aa62013-01-27 00:31:27 +02001566 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001567
Johan Hedberg890ea892013-03-15 17:06:52 -05001568 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001569
Johan Hedberg890ea892013-03-15 17:06:52 -05001570 update_class(&req);
1571 update_eir(&req);
1572
Johan Hedberg92da6092013-03-15 17:06:55 -05001573 err = hci_req_run(&req, add_uuid_complete);
1574 if (err < 0) {
1575 if (err != -ENODATA)
1576 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001577
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001578 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001579 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001580 goto failed;
1581 }
1582
1583 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001584 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001585 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001586 goto failed;
1587 }
1588
1589 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001590
1591failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001592 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001593 return err;
1594}
1595
Johan Hedberg24b78d02012-02-23 23:24:30 +02001596static bool enable_service_cache(struct hci_dev *hdev)
1597{
1598 if (!hdev_is_powered(hdev))
1599 return false;
1600
1601 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001602 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1603 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001604 return true;
1605 }
1606
1607 return false;
1608}
1609
Johan Hedberg92da6092013-03-15 17:06:55 -05001610static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1611{
1612 BT_DBG("status 0x%02x", status);
1613
1614 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1615}
1616
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001617static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001618 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001619{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001620 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001621 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001622 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001623 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 -05001624 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625 int err, found;
1626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001627 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001629 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001631 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001632 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001633 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001634 goto unlock;
1635 }
1636
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001637 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1638 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001639
Johan Hedberg24b78d02012-02-23 23:24:30 +02001640 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001641 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001642 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001643 goto unlock;
1644 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001645
Johan Hedberg9246a862012-02-23 21:33:16 +02001646 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001647 }
1648
1649 found = 0;
1650
Johan Hedberg056341c2013-01-27 00:31:30 +02001651 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001652 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1653 continue;
1654
1655 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001656 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001657 found++;
1658 }
1659
1660 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001661 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001662 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001663 goto unlock;
1664 }
1665
Johan Hedberg9246a862012-02-23 21:33:16 +02001666update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001667 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001668
Johan Hedberg890ea892013-03-15 17:06:52 -05001669 update_class(&req);
1670 update_eir(&req);
1671
Johan Hedberg92da6092013-03-15 17:06:55 -05001672 err = hci_req_run(&req, remove_uuid_complete);
1673 if (err < 0) {
1674 if (err != -ENODATA)
1675 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001676
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001677 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001678 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001679 goto unlock;
1680 }
1681
1682 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001683 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001684 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001685 goto unlock;
1686 }
1687
1688 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001689
1690unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001691 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001692 return err;
1693}
1694
Johan Hedberg92da6092013-03-15 17:06:55 -05001695static void set_class_complete(struct hci_dev *hdev, u8 status)
1696{
1697 BT_DBG("status 0x%02x", status);
1698
1699 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1700}
1701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001702static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001703 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001704{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001705 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001706 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001707 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001708 int err;
1709
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001710 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001711
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001712 if (!lmp_bredr_capable(hdev))
1713 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1714 MGMT_STATUS_NOT_SUPPORTED);
1715
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001716 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001717
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001718 if (pending_eir_or_class(hdev)) {
1719 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1720 MGMT_STATUS_BUSY);
1721 goto unlock;
1722 }
1723
1724 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1725 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1726 MGMT_STATUS_INVALID_PARAMS);
1727 goto unlock;
1728 }
1729
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001730 hdev->major_class = cp->major;
1731 hdev->minor_class = cp->minor;
1732
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001733 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001734 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001735 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001736 goto unlock;
1737 }
1738
Johan Hedberg890ea892013-03-15 17:06:52 -05001739 hci_req_init(&req, hdev);
1740
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001741 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001742 hci_dev_unlock(hdev);
1743 cancel_delayed_work_sync(&hdev->service_cache);
1744 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001745 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001746 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001747
Johan Hedberg890ea892013-03-15 17:06:52 -05001748 update_class(&req);
1749
Johan Hedberg92da6092013-03-15 17:06:55 -05001750 err = hci_req_run(&req, set_class_complete);
1751 if (err < 0) {
1752 if (err != -ENODATA)
1753 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001754
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001755 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001756 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001757 goto unlock;
1758 }
1759
1760 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001761 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001762 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001763 goto unlock;
1764 }
1765
1766 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001767
Johan Hedbergb5235a62012-02-21 14:32:24 +02001768unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001769 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001770 return err;
1771}
1772
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001773static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001774 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001775{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001776 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001777 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001778 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001779
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001780 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001781
Johan Hedberg86742e12011-11-07 23:13:38 +02001782 expected_len = sizeof(*cp) + key_count *
1783 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001784 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001785 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001786 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001787 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001788 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001789 }
1790
Johan Hedberg4ae143012013-01-20 14:27:13 +02001791 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1792 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1793 MGMT_STATUS_INVALID_PARAMS);
1794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001795 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001796 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001797
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001798 for (i = 0; i < key_count; i++) {
1799 struct mgmt_link_key_info *key = &cp->keys[i];
1800
1801 if (key->addr.type != BDADDR_BREDR)
1802 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1803 MGMT_STATUS_INVALID_PARAMS);
1804 }
1805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001806 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001807
1808 hci_link_keys_clear(hdev);
1809
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001810 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001811 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001812 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001813 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001814
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001815 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001816 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001817
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001818 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001819 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001820 }
1821
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001822 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001824 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001825
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001826 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001827}
1828
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001829static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001830 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001831{
1832 struct mgmt_ev_device_unpaired ev;
1833
1834 bacpy(&ev.addr.bdaddr, bdaddr);
1835 ev.addr.type = addr_type;
1836
1837 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001838 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001839}
1840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001843{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001844 struct mgmt_cp_unpair_device *cp = data;
1845 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001846 struct hci_cp_disconnect dc;
1847 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001848 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001849 int err;
1850
Johan Hedberga8a1d192011-11-10 15:54:38 +02001851 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001852 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1853 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001854
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001855 if (!bdaddr_type_is_valid(cp->addr.type))
1856 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1857 MGMT_STATUS_INVALID_PARAMS,
1858 &rp, sizeof(rp));
1859
Johan Hedberg118da702013-01-20 14:27:20 +02001860 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1861 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1862 MGMT_STATUS_INVALID_PARAMS,
1863 &rp, sizeof(rp));
1864
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001865 hci_dev_lock(hdev);
1866
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001867 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001868 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001869 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001870 goto unlock;
1871 }
1872
Andre Guedes591f47f2012-04-24 21:02:49 -03001873 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001874 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1875 else
1876 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001877
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001878 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001879 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001880 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001881 goto unlock;
1882 }
1883
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001884 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001885 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001886 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001887 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001888 else
1889 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001890 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001891 } else {
1892 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001893 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001894
Johan Hedberga8a1d192011-11-10 15:54:38 +02001895 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001896 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001897 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001898 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001899 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001900 }
1901
Johan Hedberg124f6e32012-02-09 13:50:12 +02001902 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001903 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001904 if (!cmd) {
1905 err = -ENOMEM;
1906 goto unlock;
1907 }
1908
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001909 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001910 dc.reason = 0x13; /* Remote User Terminated Connection */
1911 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1912 if (err < 0)
1913 mgmt_pending_remove(cmd);
1914
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001915unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001916 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001917 return err;
1918}
1919
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001920static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001921 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001922{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001923 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001924 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001925 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001926 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001927 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001928 int err;
1929
1930 BT_DBG("");
1931
Johan Hedberg06a63b12013-01-20 14:27:21 +02001932 memset(&rp, 0, sizeof(rp));
1933 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1934 rp.addr.type = cp->addr.type;
1935
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001936 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001937 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1938 MGMT_STATUS_INVALID_PARAMS,
1939 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001940
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001941 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001942
1943 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001944 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1945 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001946 goto failed;
1947 }
1948
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001949 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001950 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1951 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001952 goto failed;
1953 }
1954
Andre Guedes591f47f2012-04-24 21:02:49 -03001955 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001956 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1957 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001958 else
1959 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001960
Vishal Agarwalf9607272012-06-13 05:32:43 +05301961 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001962 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1963 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001964 goto failed;
1965 }
1966
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001967 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001968 if (!cmd) {
1969 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001970 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001971 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001972
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001973 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001974 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001975
1976 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1977 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001978 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001979
1980failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001981 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001982 return err;
1983}
1984
Andre Guedes57c14772012-04-24 21:02:50 -03001985static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001986{
1987 switch (link_type) {
1988 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001989 switch (addr_type) {
1990 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001991 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001992
Johan Hedberg48264f02011-11-09 13:58:58 +02001993 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001994 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001995 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001996 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001997
Johan Hedberg4c659c32011-11-07 23:13:39 +02001998 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001999 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002000 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002001 }
2002}
2003
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002004static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2005 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002006{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002007 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002008 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002009 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002010 int err;
2011 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002012
2013 BT_DBG("");
2014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002015 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002016
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002017 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002018 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002019 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002020 goto unlock;
2021 }
2022
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002023 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002024 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2025 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002026 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002027 }
2028
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002029 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002030 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002031 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002032 err = -ENOMEM;
2033 goto unlock;
2034 }
2035
Johan Hedberg2784eb42011-01-21 13:56:35 +02002036 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002037 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002038 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2039 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002040 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002041 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002042 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002043 continue;
2044 i++;
2045 }
2046
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002047 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002048
Johan Hedberg4c659c32011-11-07 23:13:39 +02002049 /* Recalculate length in case of filtered SCO connections, etc */
2050 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002052 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002053 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002054
Johan Hedberga38528f2011-01-22 06:46:43 +02002055 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002056
2057unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002058 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002059 return err;
2060}
2061
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002062static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002063 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002064{
2065 struct pending_cmd *cmd;
2066 int err;
2067
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002068 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002069 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002070 if (!cmd)
2071 return -ENOMEM;
2072
Johan Hedbergd8457692012-02-17 14:24:57 +02002073 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002074 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002075 if (err < 0)
2076 mgmt_pending_remove(cmd);
2077
2078 return err;
2079}
2080
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002081static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002082 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002083{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002084 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002085 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002086 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002087 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002088 int err;
2089
2090 BT_DBG("");
2091
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002092 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002093
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002094 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002095 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002096 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002097 goto failed;
2098 }
2099
Johan Hedbergd8457692012-02-17 14:24:57 +02002100 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002101 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002102 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002103 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002104 goto failed;
2105 }
2106
2107 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002108 struct mgmt_cp_pin_code_neg_reply ncp;
2109
2110 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002111
2112 BT_ERR("PIN code is not 16 bytes long");
2113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002115 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002117 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002118
2119 goto failed;
2120 }
2121
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002122 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002123 if (!cmd) {
2124 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002125 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002126 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002127
Johan Hedbergd8457692012-02-17 14:24:57 +02002128 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002129 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002130 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002131
2132 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2133 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002134 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002135
2136failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002137 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002138 return err;
2139}
2140
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002141static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2142 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002143{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002144 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002145
2146 BT_DBG("");
2147
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002148 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002149
2150 hdev->io_capability = cp->io_capability;
2151
2152 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002153 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002154
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002155 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002156
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2158 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002159}
2160
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002161static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002162{
2163 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002164 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002165
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002166 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002167 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2168 continue;
2169
Johan Hedberge9a416b2011-02-19 12:05:56 -03002170 if (cmd->user_data != conn)
2171 continue;
2172
2173 return cmd;
2174 }
2175
2176 return NULL;
2177}
2178
2179static void pairing_complete(struct pending_cmd *cmd, u8 status)
2180{
2181 struct mgmt_rp_pair_device rp;
2182 struct hci_conn *conn = cmd->user_data;
2183
Johan Hedbergba4e5642011-11-11 00:07:34 +02002184 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002185 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002186
Johan Hedbergaee9b212012-02-18 15:07:59 +02002187 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002188 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002189
2190 /* So we don't get further callbacks for this connection */
2191 conn->connect_cfm_cb = NULL;
2192 conn->security_cfm_cb = NULL;
2193 conn->disconn_cfm_cb = NULL;
2194
David Herrmann76a68ba2013-04-06 20:28:37 +02002195 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002196
Johan Hedberga664b5b2011-02-19 12:06:02 -03002197 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002198}
2199
2200static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2201{
2202 struct pending_cmd *cmd;
2203
2204 BT_DBG("status %u", status);
2205
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002206 cmd = find_pairing(conn);
2207 if (!cmd)
2208 BT_DBG("Unable to find a pending command");
2209 else
Johan Hedberge2113262012-02-18 15:20:03 +02002210 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002211}
2212
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302213static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2214{
2215 struct pending_cmd *cmd;
2216
2217 BT_DBG("status %u", status);
2218
2219 if (!status)
2220 return;
2221
2222 cmd = find_pairing(conn);
2223 if (!cmd)
2224 BT_DBG("Unable to find a pending command");
2225 else
2226 pairing_complete(cmd, mgmt_status(status));
2227}
2228
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002229static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002230 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002231{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002232 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002233 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002234 struct pending_cmd *cmd;
2235 u8 sec_level, auth_type;
2236 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002237 int err;
2238
2239 BT_DBG("");
2240
Szymon Jancf950a30e2013-01-18 12:48:07 +01002241 memset(&rp, 0, sizeof(rp));
2242 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2243 rp.addr.type = cp->addr.type;
2244
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002245 if (!bdaddr_type_is_valid(cp->addr.type))
2246 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2247 MGMT_STATUS_INVALID_PARAMS,
2248 &rp, sizeof(rp));
2249
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002250 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002251
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002252 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002253 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2254 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002255 goto unlock;
2256 }
2257
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002258 sec_level = BT_SECURITY_MEDIUM;
2259 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002260 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002261 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002262 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002263
Andre Guedes591f47f2012-04-24 21:02:49 -03002264 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002265 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2266 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002267 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002268 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2269 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002270
Ville Tervo30e76272011-02-22 16:10:53 -03002271 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002272 int status;
2273
2274 if (PTR_ERR(conn) == -EBUSY)
2275 status = MGMT_STATUS_BUSY;
2276 else
2277 status = MGMT_STATUS_CONNECT_FAILED;
2278
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002279 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002280 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002281 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002282 goto unlock;
2283 }
2284
2285 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002286 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002287 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002288 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002289 goto unlock;
2290 }
2291
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002292 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002293 if (!cmd) {
2294 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002295 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002296 goto unlock;
2297 }
2298
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002299 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002300 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002301 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302302 else
2303 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002304
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305 conn->security_cfm_cb = pairing_complete_cb;
2306 conn->disconn_cfm_cb = pairing_complete_cb;
2307 conn->io_capability = cp->io_cap;
2308 cmd->user_data = conn;
2309
2310 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002311 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002312 pairing_complete(cmd, 0);
2313
2314 err = 0;
2315
2316unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002317 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002318 return err;
2319}
2320
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002321static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2322 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002323{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002324 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002325 struct pending_cmd *cmd;
2326 struct hci_conn *conn;
2327 int err;
2328
2329 BT_DBG("");
2330
Johan Hedberg28424702012-02-02 04:02:29 +02002331 hci_dev_lock(hdev);
2332
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002333 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002334 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002335 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002336 goto unlock;
2337 }
2338
Johan Hedberg28424702012-02-02 04:02:29 +02002339 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2340 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002341 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002342 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002343 goto unlock;
2344 }
2345
2346 conn = cmd->user_data;
2347
2348 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002349 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002350 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002351 goto unlock;
2352 }
2353
2354 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2355
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002356 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002357 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002358unlock:
2359 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002360 return err;
2361}
2362
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002363static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002364 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002365 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002366{
Johan Hedberga5c29682011-02-19 12:05:57 -03002367 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002368 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002369 int err;
2370
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002371 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002372
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002373 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002374 err = cmd_complete(sk, hdev->id, mgmt_op,
2375 MGMT_STATUS_NOT_POWERED, addr,
2376 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002377 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002378 }
2379
Johan Hedberg1707c602013-03-15 17:07:15 -05002380 if (addr->type == BDADDR_BREDR)
2381 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002382 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002383 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002384
Johan Hedberg272d90d2012-02-09 15:26:12 +02002385 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002386 err = cmd_complete(sk, hdev->id, mgmt_op,
2387 MGMT_STATUS_NOT_CONNECTED, addr,
2388 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002389 goto done;
2390 }
2391
Johan Hedberg1707c602013-03-15 17:07:15 -05002392 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002393 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002394 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002395
Brian Gix5fe57d92011-12-21 16:12:13 -08002396 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002397 err = cmd_complete(sk, hdev->id, mgmt_op,
2398 MGMT_STATUS_SUCCESS, addr,
2399 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002400 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002401 err = cmd_complete(sk, hdev->id, mgmt_op,
2402 MGMT_STATUS_FAILED, addr,
2403 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002404
Brian Gix47c15e22011-11-16 13:53:14 -08002405 goto done;
2406 }
2407
Johan Hedberg1707c602013-03-15 17:07:15 -05002408 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002409 if (!cmd) {
2410 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002411 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002412 }
2413
Brian Gix0df4c182011-11-16 13:53:13 -08002414 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002415 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2416 struct hci_cp_user_passkey_reply cp;
2417
Johan Hedberg1707c602013-03-15 17:07:15 -05002418 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002419 cp.passkey = passkey;
2420 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2421 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002422 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2423 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002424
Johan Hedberga664b5b2011-02-19 12:06:02 -03002425 if (err < 0)
2426 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002427
Brian Gix0df4c182011-11-16 13:53:13 -08002428done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002429 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002430 return err;
2431}
2432
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302433static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2434 void *data, u16 len)
2435{
2436 struct mgmt_cp_pin_code_neg_reply *cp = data;
2437
2438 BT_DBG("");
2439
Johan Hedberg1707c602013-03-15 17:07:15 -05002440 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302441 MGMT_OP_PIN_CODE_NEG_REPLY,
2442 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2443}
2444
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002445static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2446 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002447{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002448 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002449
2450 BT_DBG("");
2451
2452 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002453 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002454 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002455
Johan Hedberg1707c602013-03-15 17:07:15 -05002456 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002457 MGMT_OP_USER_CONFIRM_REPLY,
2458 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002459}
2460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002462 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002463{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002464 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002465
2466 BT_DBG("");
2467
Johan Hedberg1707c602013-03-15 17:07:15 -05002468 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002469 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2470 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002471}
2472
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2474 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002475{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002476 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002477
2478 BT_DBG("");
2479
Johan Hedberg1707c602013-03-15 17:07:15 -05002480 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002481 MGMT_OP_USER_PASSKEY_REPLY,
2482 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002483}
2484
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002485static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002486 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002487{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002488 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002489
2490 BT_DBG("");
2491
Johan Hedberg1707c602013-03-15 17:07:15 -05002492 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002493 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2494 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002495}
2496
Johan Hedberg13928972013-03-15 17:07:00 -05002497static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002498{
Johan Hedberg13928972013-03-15 17:07:00 -05002499 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002500 struct hci_cp_write_local_name cp;
2501
Johan Hedberg13928972013-03-15 17:07:00 -05002502 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002503
Johan Hedberg890ea892013-03-15 17:06:52 -05002504 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002505}
2506
Johan Hedberg13928972013-03-15 17:07:00 -05002507static void set_name_complete(struct hci_dev *hdev, u8 status)
2508{
2509 struct mgmt_cp_set_local_name *cp;
2510 struct pending_cmd *cmd;
2511
2512 BT_DBG("status 0x%02x", status);
2513
2514 hci_dev_lock(hdev);
2515
2516 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2517 if (!cmd)
2518 goto unlock;
2519
2520 cp = cmd->param;
2521
2522 if (status)
2523 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2524 mgmt_status(status));
2525 else
2526 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2527 cp, sizeof(*cp));
2528
2529 mgmt_pending_remove(cmd);
2530
2531unlock:
2532 hci_dev_unlock(hdev);
2533}
2534
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002535static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002536 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002537{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002538 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002539 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002540 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002541 int err;
2542
2543 BT_DBG("");
2544
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002545 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002546
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002547 /* If the old values are the same as the new ones just return a
2548 * direct command complete event.
2549 */
2550 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2551 !memcmp(hdev->short_name, cp->short_name,
2552 sizeof(hdev->short_name))) {
2553 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2554 data, len);
2555 goto failed;
2556 }
2557
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002558 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002559
Johan Hedbergb5235a62012-02-21 14:32:24 +02002560 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002561 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002562
2563 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002564 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002565 if (err < 0)
2566 goto failed;
2567
2568 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002569 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002570
Johan Hedbergb5235a62012-02-21 14:32:24 +02002571 goto failed;
2572 }
2573
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002574 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002575 if (!cmd) {
2576 err = -ENOMEM;
2577 goto failed;
2578 }
2579
Johan Hedberg13928972013-03-15 17:07:00 -05002580 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2581
Johan Hedberg890ea892013-03-15 17:06:52 -05002582 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002583
2584 if (lmp_bredr_capable(hdev)) {
2585 update_name(&req);
2586 update_eir(&req);
2587 }
2588
2589 if (lmp_le_capable(hdev))
2590 hci_update_ad(&req);
2591
Johan Hedberg13928972013-03-15 17:07:00 -05002592 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002593 if (err < 0)
2594 mgmt_pending_remove(cmd);
2595
2596failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002597 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002598 return err;
2599}
2600
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002601static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002602 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002603{
Szymon Jancc35938b2011-03-22 13:12:21 +01002604 struct pending_cmd *cmd;
2605 int err;
2606
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002607 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002608
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002609 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002610
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002611 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002612 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002613 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002614 goto unlock;
2615 }
2616
Andre Guedes9a1a1992012-07-24 15:03:48 -03002617 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002619 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002620 goto unlock;
2621 }
2622
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002623 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002624 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002625 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002626 goto unlock;
2627 }
2628
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002629 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002630 if (!cmd) {
2631 err = -ENOMEM;
2632 goto unlock;
2633 }
2634
2635 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2636 if (err < 0)
2637 mgmt_pending_remove(cmd);
2638
2639unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002640 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002641 return err;
2642}
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002646{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002647 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002648 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002649 int err;
2650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002651 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002652
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002653 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002654
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002655 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002656 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002657 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002658 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002659 else
Szymon Janca6785be2012-12-13 15:11:21 +01002660 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002663 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002665 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002666 return err;
2667}
2668
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002669static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002670 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002671{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002672 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002673 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002674 int err;
2675
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002676 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002678 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002679
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002680 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002681 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002682 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002683 else
Szymon Janca6785be2012-12-13 15:11:21 +01002684 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002685
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002686 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002687 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002688
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002689 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002690 return err;
2691}
2692
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002693static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2694{
2695 struct pending_cmd *cmd;
2696 u8 type;
2697 int err;
2698
2699 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2700
2701 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2702 if (!cmd)
2703 return -ENOENT;
2704
2705 type = hdev->discovery.type;
2706
2707 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2708 &type, sizeof(type));
2709 mgmt_pending_remove(cmd);
2710
2711 return err;
2712}
2713
Andre Guedes7c307722013-04-30 15:29:28 -03002714static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2715{
2716 BT_DBG("status %d", status);
2717
2718 if (status) {
2719 hci_dev_lock(hdev);
2720 mgmt_start_discovery_failed(hdev, status);
2721 hci_dev_unlock(hdev);
2722 return;
2723 }
2724
2725 hci_dev_lock(hdev);
2726 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2727 hci_dev_unlock(hdev);
2728
2729 switch (hdev->discovery.type) {
2730 case DISCOV_TYPE_LE:
2731 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002732 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002733 break;
2734
2735 case DISCOV_TYPE_INTERLEAVED:
2736 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002737 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002738 break;
2739
2740 case DISCOV_TYPE_BREDR:
2741 break;
2742
2743 default:
2744 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2745 }
2746}
2747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002748static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002749 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002750{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002751 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002752 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002753 struct hci_cp_le_set_scan_param param_cp;
2754 struct hci_cp_le_set_scan_enable enable_cp;
2755 struct hci_cp_inquiry inq_cp;
2756 struct hci_request req;
2757 /* General inquiry access code (GIAC) */
2758 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002759 int err;
2760
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002761 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002762
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002763 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002764
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002765 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002766 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002767 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002768 goto failed;
2769 }
2770
Andre Guedes642be6c2012-03-21 00:03:37 -03002771 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2772 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2773 MGMT_STATUS_BUSY);
2774 goto failed;
2775 }
2776
Johan Hedbergff9ef572012-01-04 14:23:45 +02002777 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002778 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002779 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002780 goto failed;
2781 }
2782
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002783 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002784 if (!cmd) {
2785 err = -ENOMEM;
2786 goto failed;
2787 }
2788
Andre Guedes4aab14e2012-02-17 20:39:36 -03002789 hdev->discovery.type = cp->type;
2790
Andre Guedes7c307722013-04-30 15:29:28 -03002791 hci_req_init(&req, hdev);
2792
Andre Guedes4aab14e2012-02-17 20:39:36 -03002793 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002794 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002795 if (!lmp_bredr_capable(hdev)) {
2796 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2797 MGMT_STATUS_NOT_SUPPORTED);
2798 mgmt_pending_remove(cmd);
2799 goto failed;
2800 }
2801
Andre Guedes7c307722013-04-30 15:29:28 -03002802 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2803 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2804 MGMT_STATUS_BUSY);
2805 mgmt_pending_remove(cmd);
2806 goto failed;
2807 }
2808
2809 hci_inquiry_cache_flush(hdev);
2810
2811 memset(&inq_cp, 0, sizeof(inq_cp));
2812 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002813 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002814 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002815 break;
2816
2817 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002818 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002819 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002820 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2821 MGMT_STATUS_NOT_SUPPORTED);
2822 mgmt_pending_remove(cmd);
2823 goto failed;
2824 }
2825
Andre Guedes7c307722013-04-30 15:29:28 -03002826 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
2827 !lmp_bredr_capable(hdev)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002828 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2829 MGMT_STATUS_NOT_SUPPORTED);
2830 mgmt_pending_remove(cmd);
2831 goto failed;
2832 }
2833
Andre Guedes7c307722013-04-30 15:29:28 -03002834 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2835 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2836 MGMT_STATUS_REJECTED);
2837 mgmt_pending_remove(cmd);
2838 goto failed;
2839 }
2840
2841 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2842 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2843 MGMT_STATUS_BUSY);
2844 mgmt_pending_remove(cmd);
2845 goto failed;
2846 }
2847
2848 memset(&param_cp, 0, sizeof(param_cp));
2849 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002850 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2851 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002852 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2853 &param_cp);
2854
2855 memset(&enable_cp, 0, sizeof(enable_cp));
2856 enable_cp.enable = LE_SCAN_ENABLE;
2857 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2858 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2859 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002860 break;
2861
Andre Guedesf39799f2012-02-17 20:39:35 -03002862 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002863 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2864 MGMT_STATUS_INVALID_PARAMS);
2865 mgmt_pending_remove(cmd);
2866 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002867 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002868
Andre Guedes7c307722013-04-30 15:29:28 -03002869 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002870 if (err < 0)
2871 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002872 else
2873 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002874
2875failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002876 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002877 return err;
2878}
2879
Andre Guedes1183fdc2013-04-30 15:29:35 -03002880static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2881{
2882 struct pending_cmd *cmd;
2883 int err;
2884
2885 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2886 if (!cmd)
2887 return -ENOENT;
2888
2889 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2890 &hdev->discovery.type, sizeof(hdev->discovery.type));
2891 mgmt_pending_remove(cmd);
2892
2893 return err;
2894}
2895
Andre Guedes0e05bba2013-04-30 15:29:33 -03002896static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2897{
2898 BT_DBG("status %d", status);
2899
2900 hci_dev_lock(hdev);
2901
2902 if (status) {
2903 mgmt_stop_discovery_failed(hdev, status);
2904 goto unlock;
2905 }
2906
2907 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2908
2909unlock:
2910 hci_dev_unlock(hdev);
2911}
2912
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002913static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002914 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002915{
Johan Hedbergd9306502012-02-20 23:25:18 +02002916 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002917 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002918 struct hci_cp_remote_name_req_cancel cp;
2919 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002920 struct hci_request req;
2921 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002922 int err;
2923
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002924 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002925
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002926 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002927
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002928 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002929 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002930 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2931 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002932 goto unlock;
2933 }
2934
2935 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002936 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002937 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2938 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002939 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002940 }
2941
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002942 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002943 if (!cmd) {
2944 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002945 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002946 }
2947
Andre Guedes0e05bba2013-04-30 15:29:33 -03002948 hci_req_init(&req, hdev);
2949
Andre Guedese0d9727e2012-03-20 15:15:36 -03002950 switch (hdev->discovery.state) {
2951 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002952 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2953 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2954 } else {
2955 cancel_delayed_work(&hdev->le_scan_disable);
2956
2957 memset(&enable_cp, 0, sizeof(enable_cp));
2958 enable_cp.enable = LE_SCAN_DISABLE;
2959 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2960 sizeof(enable_cp), &enable_cp);
2961 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002962
Andre Guedese0d9727e2012-03-20 15:15:36 -03002963 break;
2964
2965 case DISCOVERY_RESOLVING:
2966 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002967 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002968 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002969 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002970 err = cmd_complete(sk, hdev->id,
2971 MGMT_OP_STOP_DISCOVERY, 0,
2972 &mgmt_cp->type,
2973 sizeof(mgmt_cp->type));
2974 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2975 goto unlock;
2976 }
2977
2978 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002979 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2980 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002981
2982 break;
2983
2984 default:
2985 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002986
2987 mgmt_pending_remove(cmd);
2988 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
2989 MGMT_STATUS_FAILED, &mgmt_cp->type,
2990 sizeof(mgmt_cp->type));
2991 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002992 }
2993
Andre Guedes0e05bba2013-04-30 15:29:33 -03002994 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002995 if (err < 0)
2996 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002997 else
2998 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002999
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003000unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003001 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003002 return err;
3003}
3004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003005static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003006 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003007{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003008 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003009 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003010 int err;
3011
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003012 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003013
Johan Hedberg561aafb2012-01-04 13:31:59 +02003014 hci_dev_lock(hdev);
3015
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003016 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003017 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003019 goto failed;
3020 }
3021
Johan Hedberga198e7b2012-02-17 14:27:06 +02003022 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003023 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003024 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003025 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003026 goto failed;
3027 }
3028
3029 if (cp->name_known) {
3030 e->name_state = NAME_KNOWN;
3031 list_del(&e->list);
3032 } else {
3033 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003034 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003035 }
3036
Johan Hedberge3846622013-01-09 15:29:33 +02003037 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3038 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003039
3040failed:
3041 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003042 return err;
3043}
3044
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003045static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003046 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003047{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003048 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003049 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003050 int err;
3051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003052 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003053
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003054 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003055 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3056 MGMT_STATUS_INVALID_PARAMS,
3057 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003058
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003059 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003060
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003061 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003062 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003063 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003064 else
Szymon Janca6785be2012-12-13 15:11:21 +01003065 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003066
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003067 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003068 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003069
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003070 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003071
3072 return err;
3073}
3074
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003075static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003076 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003077{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003078 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003079 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003080 int err;
3081
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003082 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003083
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003084 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003085 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3086 MGMT_STATUS_INVALID_PARAMS,
3087 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003089 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003090
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003091 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003092 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003093 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003094 else
Szymon Janca6785be2012-12-13 15:11:21 +01003095 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003097 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003098 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003099
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003100 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003101
3102 return err;
3103}
3104
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003105static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3106 u16 len)
3107{
3108 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003109 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003110 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003111 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003112
3113 BT_DBG("%s", hdev->name);
3114
Szymon Jancc72d4b82012-03-16 16:02:57 +01003115 source = __le16_to_cpu(cp->source);
3116
3117 if (source > 0x0002)
3118 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3119 MGMT_STATUS_INVALID_PARAMS);
3120
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003121 hci_dev_lock(hdev);
3122
Szymon Jancc72d4b82012-03-16 16:02:57 +01003123 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003124 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3125 hdev->devid_product = __le16_to_cpu(cp->product);
3126 hdev->devid_version = __le16_to_cpu(cp->version);
3127
3128 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3129
Johan Hedberg890ea892013-03-15 17:06:52 -05003130 hci_req_init(&req, hdev);
3131 update_eir(&req);
3132 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003133
3134 hci_dev_unlock(hdev);
3135
3136 return err;
3137}
3138
Johan Hedberg33e38b32013-03-15 17:07:05 -05003139static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3140{
3141 struct pending_cmd *cmd;
3142
3143 BT_DBG("status 0x%02x", status);
3144
3145 hci_dev_lock(hdev);
3146
3147 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3148 if (!cmd)
3149 goto unlock;
3150
3151 if (status) {
3152 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3153 mgmt_status(status));
3154 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003155 struct mgmt_mode *cp = cmd->param;
3156
3157 if (cp->val)
3158 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3159 else
3160 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3161
Johan Hedberg33e38b32013-03-15 17:07:05 -05003162 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3163 new_settings(hdev, cmd->sk);
3164 }
3165
3166 mgmt_pending_remove(cmd);
3167
3168unlock:
3169 hci_dev_unlock(hdev);
3170}
3171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003172static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003173 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003174{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003175 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003176 struct pending_cmd *cmd;
3177 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003178 int err;
3179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003180 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003181
Johan Hedberg1a47aee2013-03-15 17:07:06 -05003182 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003183 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3184 MGMT_STATUS_NOT_SUPPORTED);
3185
Johan Hedberga7e80f22013-01-09 16:05:19 +02003186 if (cp->val != 0x00 && cp->val != 0x01)
3187 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3188 MGMT_STATUS_INVALID_PARAMS);
3189
Johan Hedberg5400c042012-02-21 16:40:33 +02003190 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003191 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003192 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003193
3194 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003195 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003196 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003197
3198 hci_dev_lock(hdev);
3199
Johan Hedberg05cbf292013-03-15 17:07:07 -05003200 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3201 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3202 MGMT_STATUS_BUSY);
3203 goto unlock;
3204 }
3205
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003206 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3207 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3208 hdev);
3209 goto unlock;
3210 }
3211
Johan Hedberg33e38b32013-03-15 17:07:05 -05003212 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3213 data, len);
3214 if (!cmd) {
3215 err = -ENOMEM;
3216 goto unlock;
3217 }
3218
3219 hci_req_init(&req, hdev);
3220
Johan Hedberg406d7802013-03-15 17:07:09 -05003221 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003222
3223 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003224 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003225 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003226 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003227 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003228 }
3229
Johan Hedberg33e38b32013-03-15 17:07:05 -05003230unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003231 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003232
Antti Julkuf6422ec2011-06-22 13:11:56 +03003233 return err;
3234}
3235
Johan Hedberg3f706b72013-01-20 14:27:16 +02003236static bool ltk_is_valid(struct mgmt_ltk_info *key)
3237{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003238 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3239 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003240 if (key->master != 0x00 && key->master != 0x01)
3241 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003242 if (!bdaddr_type_is_le(key->addr.type))
3243 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003244 return true;
3245}
3246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003247static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003248 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003249{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003250 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3251 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003252 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003253
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003254 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003255
3256 expected_len = sizeof(*cp) + key_count *
3257 sizeof(struct mgmt_ltk_info);
3258 if (expected_len != len) {
3259 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003260 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003261 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003262 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003263 }
3264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003265 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003266
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003267 for (i = 0; i < key_count; i++) {
3268 struct mgmt_ltk_info *key = &cp->keys[i];
3269
Johan Hedberg3f706b72013-01-20 14:27:16 +02003270 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003271 return cmd_status(sk, hdev->id,
3272 MGMT_OP_LOAD_LONG_TERM_KEYS,
3273 MGMT_STATUS_INVALID_PARAMS);
3274 }
3275
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003276 hci_dev_lock(hdev);
3277
3278 hci_smp_ltks_clear(hdev);
3279
3280 for (i = 0; i < key_count; i++) {
3281 struct mgmt_ltk_info *key = &cp->keys[i];
3282 u8 type;
3283
3284 if (key->master)
3285 type = HCI_SMP_LTK;
3286 else
3287 type = HCI_SMP_LTK_SLAVE;
3288
Hemant Gupta4596fde2012-04-16 14:57:40 +05303289 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003290 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003291 type, 0, key->authenticated, key->val,
3292 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003293 }
3294
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003295 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3296 NULL, 0);
3297
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003298 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003299
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003300 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003301}
3302
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003303static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003304 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3305 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003306 bool var_len;
3307 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003308} mgmt_handlers[] = {
3309 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003310 { read_version, false, MGMT_READ_VERSION_SIZE },
3311 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3312 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3313 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3314 { set_powered, false, MGMT_SETTING_SIZE },
3315 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3316 { set_connectable, false, MGMT_SETTING_SIZE },
3317 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3318 { set_pairable, false, MGMT_SETTING_SIZE },
3319 { set_link_security, false, MGMT_SETTING_SIZE },
3320 { set_ssp, false, MGMT_SETTING_SIZE },
3321 { set_hs, false, MGMT_SETTING_SIZE },
3322 { set_le, false, MGMT_SETTING_SIZE },
3323 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3324 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3325 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3326 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3327 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3328 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3329 { disconnect, false, MGMT_DISCONNECT_SIZE },
3330 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3331 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3332 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3333 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3334 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3335 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3336 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3337 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3338 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3339 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3340 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3341 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3342 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3343 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3344 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3345 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3346 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3347 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3348 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003349 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003350};
3351
3352
Johan Hedberg03811012010-12-08 00:21:06 +02003353int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3354{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003355 void *buf;
3356 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003357 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003358 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003359 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003360 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003361 int err;
3362
3363 BT_DBG("got %zu bytes", msglen);
3364
3365 if (msglen < sizeof(*hdr))
3366 return -EINVAL;
3367
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003368 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003369 if (!buf)
3370 return -ENOMEM;
3371
3372 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3373 err = -EFAULT;
3374 goto done;
3375 }
3376
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003377 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003378 opcode = __le16_to_cpu(hdr->opcode);
3379 index = __le16_to_cpu(hdr->index);
3380 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003381
3382 if (len != msglen - sizeof(*hdr)) {
3383 err = -EINVAL;
3384 goto done;
3385 }
3386
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003387 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003388 hdev = hci_dev_get(index);
3389 if (!hdev) {
3390 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003391 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003392 goto done;
3393 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003394
3395 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3396 err = cmd_status(sk, index, opcode,
3397 MGMT_STATUS_INVALID_INDEX);
3398 goto done;
3399 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003400 }
3401
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003402 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003403 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003404 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003405 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003406 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003407 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003408 }
3409
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003410 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003411 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003412 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003413 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003414 goto done;
3415 }
3416
Johan Hedbergbe22b542012-03-01 22:24:41 +02003417 handler = &mgmt_handlers[opcode];
3418
3419 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003420 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003421 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003422 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003423 goto done;
3424 }
3425
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003426 if (hdev)
3427 mgmt_init_hdev(sk, hdev);
3428
3429 cp = buf + sizeof(*hdr);
3430
Johan Hedbergbe22b542012-03-01 22:24:41 +02003431 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003432 if (err < 0)
3433 goto done;
3434
Johan Hedberg03811012010-12-08 00:21:06 +02003435 err = msglen;
3436
3437done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003438 if (hdev)
3439 hci_dev_put(hdev);
3440
Johan Hedberg03811012010-12-08 00:21:06 +02003441 kfree(buf);
3442 return err;
3443}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003444
Johan Hedberg744cf192011-11-08 20:40:14 +02003445int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003446{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003447 if (!mgmt_valid_hdev(hdev))
3448 return -ENOTSUPP;
3449
Johan Hedberg744cf192011-11-08 20:40:14 +02003450 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003451}
3452
Johan Hedberg744cf192011-11-08 20:40:14 +02003453int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003454{
Johan Hedberg5f159032012-03-02 03:13:19 +02003455 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003456
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003457 if (!mgmt_valid_hdev(hdev))
3458 return -ENOTSUPP;
3459
Johan Hedberg744cf192011-11-08 20:40:14 +02003460 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003461
Johan Hedberg744cf192011-11-08 20:40:14 +02003462 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003463}
3464
Johan Hedberg890ea892013-03-15 17:06:52 -05003465static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003466{
Johan Hedberg890ea892013-03-15 17:06:52 -05003467 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003468 u8 scan = 0;
3469
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003470 /* Ensure that fast connectable is disabled. This function will
3471 * not do anything if the page scan parameters are already what
3472 * they should be.
3473 */
3474 write_fast_connectable(req, false);
3475
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003476 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3477 scan |= SCAN_PAGE;
3478 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3479 scan |= SCAN_INQUIRY;
3480
Johan Hedberg890ea892013-03-15 17:06:52 -05003481 if (scan)
3482 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003483}
3484
Johan Hedberg229ab392013-03-15 17:06:53 -05003485static void powered_complete(struct hci_dev *hdev, u8 status)
3486{
3487 struct cmd_lookup match = { NULL, hdev };
3488
3489 BT_DBG("status 0x%02x", status);
3490
3491 hci_dev_lock(hdev);
3492
3493 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3494
3495 new_settings(hdev, match.sk);
3496
3497 hci_dev_unlock(hdev);
3498
3499 if (match.sk)
3500 sock_put(match.sk);
3501}
3502
Johan Hedberg70da6242013-03-15 17:06:51 -05003503static int powered_update_hci(struct hci_dev *hdev)
3504{
Johan Hedberg890ea892013-03-15 17:06:52 -05003505 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003506 u8 link_sec;
3507
Johan Hedberg890ea892013-03-15 17:06:52 -05003508 hci_req_init(&req, hdev);
3509
Johan Hedberg70da6242013-03-15 17:06:51 -05003510 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3511 !lmp_host_ssp_capable(hdev)) {
3512 u8 ssp = 1;
3513
Johan Hedberg890ea892013-03-15 17:06:52 -05003514 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003515 }
3516
Johan Hedbergc73eee92013-04-19 18:35:21 +03003517 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3518 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003519 struct hci_cp_write_le_host_supported cp;
3520
3521 cp.le = 1;
3522 cp.simul = lmp_le_br_capable(hdev);
3523
3524 /* Check first if we already have the right
3525 * host state (host features set)
3526 */
3527 if (cp.le != lmp_host_le_capable(hdev) ||
3528 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003529 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3530 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003531 }
3532
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003533 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
3534 u8 adv = 0x01;
3535
3536 hci_req_add(&req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(adv), &adv);
3537 }
3538
Johan Hedberg70da6242013-03-15 17:06:51 -05003539 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3540 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003541 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3542 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003543
3544 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003545 set_bredr_scan(&req);
3546 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003547 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003548 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003549 }
3550
Johan Hedberg229ab392013-03-15 17:06:53 -05003551 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003552}
3553
Johan Hedberg744cf192011-11-08 20:40:14 +02003554int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003555{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003556 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003557 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3558 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003559 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003560
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003561 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3562 return 0;
3563
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003564 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003565 if (powered_update_hci(hdev) == 0)
3566 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003567
Johan Hedberg229ab392013-03-15 17:06:53 -05003568 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3569 &match);
3570 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003571 }
3572
Johan Hedberg229ab392013-03-15 17:06:53 -05003573 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3574 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3575
3576 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3577 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3578 zero_cod, sizeof(zero_cod), NULL);
3579
3580new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003581 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003582
3583 if (match.sk)
3584 sock_put(match.sk);
3585
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003586 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003587}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003588
Johan Hedberg96570ff2013-05-29 09:51:29 +03003589int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3590{
3591 struct pending_cmd *cmd;
3592 u8 status;
3593
3594 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3595 if (!cmd)
3596 return -ENOENT;
3597
3598 if (err == -ERFKILL)
3599 status = MGMT_STATUS_RFKILLED;
3600 else
3601 status = MGMT_STATUS_FAILED;
3602
3603 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3604
3605 mgmt_pending_remove(cmd);
3606
3607 return err;
3608}
3609
Johan Hedberg744cf192011-11-08 20:40:14 +02003610int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003611{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003612 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003613 bool changed = false;
3614 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003615
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003616 if (discoverable) {
3617 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3618 changed = true;
3619 } else {
3620 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3621 changed = true;
3622 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003623
Johan Hedberged9b5f22012-02-21 20:47:06 +02003624 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003625 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003626
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003627 if (changed)
3628 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003629
Johan Hedberg73f22f62010-12-29 16:00:25 +02003630 if (match.sk)
3631 sock_put(match.sk);
3632
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003633 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003634}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003635
Johan Hedberg744cf192011-11-08 20:40:14 +02003636int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003637{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003638 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003639 bool changed = false;
3640 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003641
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003642 if (connectable) {
3643 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3644 changed = true;
3645 } else {
3646 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3647 changed = true;
3648 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003649
Johan Hedberg2b76f452013-03-15 17:07:04 -05003650 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003651
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003652 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003653 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003654
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003655 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003656}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003657
Johan Hedberg744cf192011-11-08 20:40:14 +02003658int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003659{
Johan Hedbergca69b792011-11-11 18:10:00 +02003660 u8 mgmt_err = mgmt_status(status);
3661
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003662 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003663 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003664 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003665
3666 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003667 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003668 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003669
3670 return 0;
3671}
3672
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003673int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3674 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003675{
Johan Hedberg86742e12011-11-07 23:13:38 +02003676 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003677
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003678 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003679
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003680 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003681 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003682 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003683 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003684 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003685 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003686
Johan Hedberg744cf192011-11-08 20:40:14 +02003687 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003688}
Johan Hedbergf7520542011-01-20 12:34:39 +02003689
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003690int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3691{
3692 struct mgmt_ev_new_long_term_key ev;
3693
3694 memset(&ev, 0, sizeof(ev));
3695
3696 ev.store_hint = persistent;
3697 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003698 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003699 ev.key.authenticated = key->authenticated;
3700 ev.key.enc_size = key->enc_size;
3701 ev.key.ediv = key->ediv;
3702
3703 if (key->type == HCI_SMP_LTK)
3704 ev.key.master = 1;
3705
3706 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3707 memcpy(ev.key.val, key->val, sizeof(key->val));
3708
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003709 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3710 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003711}
3712
Johan Hedbergafc747a2012-01-15 18:11:07 +02003713int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003714 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3715 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003716{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003717 char buf[512];
3718 struct mgmt_ev_device_connected *ev = (void *) buf;
3719 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003720
Johan Hedbergb644ba32012-01-17 21:48:47 +02003721 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003722 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003723
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003724 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003725
Johan Hedbergb644ba32012-01-17 21:48:47 +02003726 if (name_len > 0)
3727 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003728 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003729
3730 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003731 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003732 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003733
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003734 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003735
3736 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003737 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003738}
3739
Johan Hedberg8962ee72011-01-20 12:40:27 +02003740static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3741{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003742 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003743 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003744 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003745
Johan Hedberg88c3df12012-02-09 14:27:38 +02003746 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3747 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003748
Johan Hedbergaee9b212012-02-18 15:07:59 +02003749 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003750 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003751
3752 *sk = cmd->sk;
3753 sock_hold(*sk);
3754
Johan Hedberga664b5b2011-02-19 12:06:02 -03003755 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003756}
3757
Johan Hedberg124f6e32012-02-09 13:50:12 +02003758static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003759{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003760 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003761 struct mgmt_cp_unpair_device *cp = cmd->param;
3762 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003763
3764 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003765 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3766 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003767
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003768 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3769
Johan Hedbergaee9b212012-02-18 15:07:59 +02003770 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003771
3772 mgmt_pending_remove(cmd);
3773}
3774
Johan Hedbergafc747a2012-01-15 18:11:07 +02003775int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003776 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003777{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003778 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003779 struct sock *sk = NULL;
3780 int err;
3781
Johan Hedberg744cf192011-11-08 20:40:14 +02003782 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003783
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003784 bacpy(&ev.addr.bdaddr, bdaddr);
3785 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3786 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003787
Johan Hedbergafc747a2012-01-15 18:11:07 +02003788 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003789 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003790
3791 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003792 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003793
Johan Hedberg124f6e32012-02-09 13:50:12 +02003794 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003795 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003796
Johan Hedberg8962ee72011-01-20 12:40:27 +02003797 return err;
3798}
3799
Johan Hedberg88c3df12012-02-09 14:27:38 +02003800int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003801 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003802{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003803 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003804 struct pending_cmd *cmd;
3805 int err;
3806
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003807 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3808 hdev);
3809
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003810 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003811 if (!cmd)
3812 return -ENOENT;
3813
Johan Hedberg88c3df12012-02-09 14:27:38 +02003814 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003815 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003816
Johan Hedberg88c3df12012-02-09 14:27:38 +02003817 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003818 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003819
Johan Hedberga664b5b2011-02-19 12:06:02 -03003820 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003821
3822 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003823}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003824
Johan Hedberg48264f02011-11-09 13:58:58 +02003825int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003826 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003827{
3828 struct mgmt_ev_connect_failed ev;
3829
Johan Hedberg4c659c32011-11-07 23:13:39 +02003830 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003831 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003832 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003833
Johan Hedberg744cf192011-11-08 20:40:14 +02003834 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003835}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003836
Johan Hedberg744cf192011-11-08 20:40:14 +02003837int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003838{
3839 struct mgmt_ev_pin_code_request ev;
3840
Johan Hedbergd8457692012-02-17 14:24:57 +02003841 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003842 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003843 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003844
Johan Hedberg744cf192011-11-08 20:40:14 +02003845 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003846 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003847}
3848
Johan Hedberg744cf192011-11-08 20:40:14 +02003849int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003850 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003851{
3852 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003853 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003854 int err;
3855
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003856 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003857 if (!cmd)
3858 return -ENOENT;
3859
Johan Hedbergd8457692012-02-17 14:24:57 +02003860 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003861 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003862
Johan Hedbergaee9b212012-02-18 15:07:59 +02003863 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003864 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003865
Johan Hedberga664b5b2011-02-19 12:06:02 -03003866 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003867
3868 return err;
3869}
3870
Johan Hedberg744cf192011-11-08 20:40:14 +02003871int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003872 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003873{
3874 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003875 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003876 int err;
3877
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003878 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003879 if (!cmd)
3880 return -ENOENT;
3881
Johan Hedbergd8457692012-02-17 14:24:57 +02003882 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003883 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003884
Johan Hedbergaee9b212012-02-18 15:07:59 +02003885 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003886 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003887
Johan Hedberga664b5b2011-02-19 12:06:02 -03003888 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003889
3890 return err;
3891}
Johan Hedberga5c29682011-02-19 12:05:57 -03003892
Johan Hedberg744cf192011-11-08 20:40:14 +02003893int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003894 u8 link_type, u8 addr_type, __le32 value,
3895 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003896{
3897 struct mgmt_ev_user_confirm_request ev;
3898
Johan Hedberg744cf192011-11-08 20:40:14 +02003899 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003900
Johan Hedberg272d90d2012-02-09 15:26:12 +02003901 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003902 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003903 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003904 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003905
Johan Hedberg744cf192011-11-08 20:40:14 +02003906 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003907 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003908}
3909
Johan Hedberg272d90d2012-02-09 15:26:12 +02003910int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003911 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003912{
3913 struct mgmt_ev_user_passkey_request ev;
3914
3915 BT_DBG("%s", hdev->name);
3916
Johan Hedberg272d90d2012-02-09 15:26:12 +02003917 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003918 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003919
3920 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003921 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003922}
3923
Brian Gix0df4c182011-11-16 13:53:13 -08003924static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003925 u8 link_type, u8 addr_type, u8 status,
3926 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003927{
3928 struct pending_cmd *cmd;
3929 struct mgmt_rp_user_confirm_reply rp;
3930 int err;
3931
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003932 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003933 if (!cmd)
3934 return -ENOENT;
3935
Johan Hedberg272d90d2012-02-09 15:26:12 +02003936 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003937 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003938 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003939 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003940
Johan Hedberga664b5b2011-02-19 12:06:02 -03003941 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003942
3943 return err;
3944}
3945
Johan Hedberg744cf192011-11-08 20:40:14 +02003946int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003947 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003948{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003949 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003950 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003951}
3952
Johan Hedberg272d90d2012-02-09 15:26:12 +02003953int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003954 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003955{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003956 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003957 status,
3958 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003959}
Johan Hedberg2a611692011-02-19 12:06:00 -03003960
Brian Gix604086b2011-11-23 08:28:33 -08003961int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003962 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003963{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003964 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003965 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003966}
3967
Johan Hedberg272d90d2012-02-09 15:26:12 +02003968int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003969 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003970{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003971 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003972 status,
3973 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003974}
3975
Johan Hedberg92a25252012-09-06 18:39:26 +03003976int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3977 u8 link_type, u8 addr_type, u32 passkey,
3978 u8 entered)
3979{
3980 struct mgmt_ev_passkey_notify ev;
3981
3982 BT_DBG("%s", hdev->name);
3983
3984 bacpy(&ev.addr.bdaddr, bdaddr);
3985 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3986 ev.passkey = __cpu_to_le32(passkey);
3987 ev.entered = entered;
3988
3989 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3990}
3991
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003992int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003993 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003994{
3995 struct mgmt_ev_auth_failed ev;
3996
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003997 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003998 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003999 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004000
Johan Hedberg744cf192011-11-08 20:40:14 +02004001 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004002}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004003
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004004int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4005{
4006 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004007 bool changed = false;
4008 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004009
4010 if (status) {
4011 u8 mgmt_err = mgmt_status(status);
4012 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004013 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004014 return 0;
4015 }
4016
Johan Hedberg47990ea2012-02-22 11:58:37 +02004017 if (test_bit(HCI_AUTH, &hdev->flags)) {
4018 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4019 changed = true;
4020 } else {
4021 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4022 changed = true;
4023 }
4024
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004025 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004026 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004027
Johan Hedberg47990ea2012-02-22 11:58:37 +02004028 if (changed)
4029 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004030
4031 if (match.sk)
4032 sock_put(match.sk);
4033
4034 return err;
4035}
4036
Johan Hedberg890ea892013-03-15 17:06:52 -05004037static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004038{
Johan Hedberg890ea892013-03-15 17:06:52 -05004039 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004040 struct hci_cp_write_eir cp;
4041
Johan Hedberg976eb202012-10-24 21:12:01 +03004042 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004043 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004044
Johan Hedbergc80da272012-02-22 15:38:48 +02004045 memset(hdev->eir, 0, sizeof(hdev->eir));
4046
Johan Hedbergcacaf522012-02-21 00:52:42 +02004047 memset(&cp, 0, sizeof(cp));
4048
Johan Hedberg890ea892013-03-15 17:06:52 -05004049 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004050}
4051
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004052int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004053{
4054 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004055 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004056 bool changed = false;
4057 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004058
4059 if (status) {
4060 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004061
4062 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004063 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004064 err = new_settings(hdev, NULL);
4065
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004066 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4067 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004068
4069 return err;
4070 }
4071
4072 if (enable) {
4073 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4074 changed = true;
4075 } else {
4076 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4077 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004078 }
4079
4080 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4081
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004082 if (changed)
4083 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004084
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004085 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004086 sock_put(match.sk);
4087
Johan Hedberg890ea892013-03-15 17:06:52 -05004088 hci_req_init(&req, hdev);
4089
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004090 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004091 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004092 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004093 clear_eir(&req);
4094
4095 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004096
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004097 return err;
4098}
4099
Johan Hedberg92da6092013-03-15 17:06:55 -05004100static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004101{
4102 struct cmd_lookup *match = data;
4103
Johan Hedberg90e70452012-02-23 23:09:40 +02004104 if (match->sk == NULL) {
4105 match->sk = cmd->sk;
4106 sock_hold(match->sk);
4107 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004108}
4109
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004110int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004111 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004112{
Johan Hedberg90e70452012-02-23 23:09:40 +02004113 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4114 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004115
Johan Hedberg92da6092013-03-15 17:06:55 -05004116 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4117 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4118 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004119
4120 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004121 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4122 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004123
4124 if (match.sk)
4125 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004126
4127 return err;
4128}
4129
Johan Hedberg744cf192011-11-08 20:40:14 +02004130int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004131{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004132 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004133 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004134
Johan Hedberg13928972013-03-15 17:07:00 -05004135 if (status)
4136 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004137
4138 memset(&ev, 0, sizeof(ev));
4139 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004140 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004141
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004142 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004143 if (!cmd) {
4144 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004145
Johan Hedberg13928972013-03-15 17:07:00 -05004146 /* If this is a HCI command related to powering on the
4147 * HCI dev don't send any mgmt signals.
4148 */
4149 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4150 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004151 }
4152
Johan Hedberg13928972013-03-15 17:07:00 -05004153 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4154 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004155}
Szymon Jancc35938b2011-03-22 13:12:21 +01004156
Johan Hedberg744cf192011-11-08 20:40:14 +02004157int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004158 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004159{
4160 struct pending_cmd *cmd;
4161 int err;
4162
Johan Hedberg744cf192011-11-08 20:40:14 +02004163 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004164
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004165 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004166 if (!cmd)
4167 return -ENOENT;
4168
4169 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004170 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4171 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004172 } else {
4173 struct mgmt_rp_read_local_oob_data rp;
4174
4175 memcpy(rp.hash, hash, sizeof(rp.hash));
4176 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4177
Johan Hedberg744cf192011-11-08 20:40:14 +02004178 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004179 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4180 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004181 }
4182
4183 mgmt_pending_remove(cmd);
4184
4185 return err;
4186}
Johan Hedberge17acd42011-03-30 23:57:16 +03004187
Johan Hedberg48264f02011-11-09 13:58:58 +02004188int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004189 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4190 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004191{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004192 char buf[512];
4193 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004194 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004195
Andre Guedes12602d02013-04-30 15:29:40 -03004196 if (!hci_discovery_active(hdev))
4197 return -EPERM;
4198
Johan Hedberg1dc06092012-01-15 21:01:23 +02004199 /* Leave 5 bytes for a potential CoD field */
4200 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004201 return -EINVAL;
4202
Johan Hedberg1dc06092012-01-15 21:01:23 +02004203 memset(buf, 0, sizeof(buf));
4204
Johan Hedberge319d2e2012-01-15 19:51:59 +02004205 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004206 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004207 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004208 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304209 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004210 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304211 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004212
Johan Hedberg1dc06092012-01-15 21:01:23 +02004213 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004214 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004215
Johan Hedberg1dc06092012-01-15 21:01:23 +02004216 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4217 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004218 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004219
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004220 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004221 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004222
Johan Hedberge319d2e2012-01-15 19:51:59 +02004223 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004224}
Johan Hedberga88a9652011-03-30 13:18:12 +03004225
Johan Hedbergb644ba32012-01-17 21:48:47 +02004226int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004227 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004228{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004229 struct mgmt_ev_device_found *ev;
4230 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4231 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004232
Johan Hedbergb644ba32012-01-17 21:48:47 +02004233 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004234
Johan Hedbergb644ba32012-01-17 21:48:47 +02004235 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004236
Johan Hedbergb644ba32012-01-17 21:48:47 +02004237 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004238 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004239 ev->rssi = rssi;
4240
4241 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004242 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004243
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004244 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004245
Johan Hedberg053c7e02012-02-04 00:06:00 +02004246 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004247 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004248}
Johan Hedberg314b2382011-04-27 10:29:57 -04004249
Johan Hedberg744cf192011-11-08 20:40:14 +02004250int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004251{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004252 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004253 struct pending_cmd *cmd;
4254
Andre Guedes343fb142011-11-22 17:14:19 -03004255 BT_DBG("%s discovering %u", hdev->name, discovering);
4256
Johan Hedberg164a6e72011-11-01 17:06:44 +02004257 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004258 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004259 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004260 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004261
4262 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004263 u8 type = hdev->discovery.type;
4264
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004265 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4266 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004267 mgmt_pending_remove(cmd);
4268 }
4269
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004270 memset(&ev, 0, sizeof(ev));
4271 ev.type = hdev->discovery.type;
4272 ev.discovering = discovering;
4273
4274 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004275}
Antti Julku5e762442011-08-25 16:48:02 +03004276
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004277int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004278{
4279 struct pending_cmd *cmd;
4280 struct mgmt_ev_device_blocked ev;
4281
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004282 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004283
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004284 bacpy(&ev.addr.bdaddr, bdaddr);
4285 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004286
Johan Hedberg744cf192011-11-08 20:40:14 +02004287 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004288 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004289}
4290
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004291int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004292{
4293 struct pending_cmd *cmd;
4294 struct mgmt_ev_device_unblocked ev;
4295
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004296 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004297
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004298 bacpy(&ev.addr.bdaddr, bdaddr);
4299 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004300
Johan Hedberg744cf192011-11-08 20:40:14 +02004301 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004302 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004303}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01004304
4305module_param(enable_hs, bool, 0644);
4306MODULE_PARM_DESC(enable_hs, "Enable High Speed support");