blob: 85bfa2157e6f71b1fbaa21dabec57626e13ef4a4 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060038#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800105#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200106
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200107#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
108 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
109
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200110struct pending_cmd {
111 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200112 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100114 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200115 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300116 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117};
118
Johan Hedbergca69b792011-11-11 18:10:00 +0200119/* HCI to MGMT error code conversion table */
120static u8 mgmt_status_table[] = {
121 MGMT_STATUS_SUCCESS,
122 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
123 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
124 MGMT_STATUS_FAILED, /* Hardware Failure */
125 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
126 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
127 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
128 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
129 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
130 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
132 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
133 MGMT_STATUS_BUSY, /* Command Disallowed */
134 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
135 MGMT_STATUS_REJECTED, /* Rejected Security */
136 MGMT_STATUS_REJECTED, /* Rejected Personal */
137 MGMT_STATUS_TIMEOUT, /* Host Timeout */
138 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
139 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
140 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
141 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
142 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
143 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
144 MGMT_STATUS_BUSY, /* Repeated Attempts */
145 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
146 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
147 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
148 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
149 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
150 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
151 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
152 MGMT_STATUS_FAILED, /* Unspecified Error */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
154 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
155 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
156 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
157 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
158 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
159 MGMT_STATUS_FAILED, /* Unit Link Key Used */
160 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
161 MGMT_STATUS_TIMEOUT, /* Instant Passed */
162 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
163 MGMT_STATUS_FAILED, /* Transaction Collision */
164 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
165 MGMT_STATUS_REJECTED, /* QoS Rejected */
166 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
167 MGMT_STATUS_REJECTED, /* Insufficient Security */
168 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
169 MGMT_STATUS_BUSY, /* Role Switch Pending */
170 MGMT_STATUS_FAILED, /* Slot Violation */
171 MGMT_STATUS_FAILED, /* Role Switch Failed */
172 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
173 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
174 MGMT_STATUS_BUSY, /* Host Busy Pairing */
175 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
176 MGMT_STATUS_BUSY, /* Controller Busy */
177 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
178 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
179 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
180 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
181 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
182};
183
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300184bool mgmt_valid_hdev(struct hci_dev *hdev)
185{
186 return hdev->dev_type == HCI_BREDR;
187}
188
Johan Hedbergca69b792011-11-11 18:10:00 +0200189static u8 mgmt_status(u8 hci_status)
190{
191 if (hci_status < ARRAY_SIZE(mgmt_status_table))
192 return mgmt_status_table[hci_status];
193
194 return MGMT_STATUS_FAILED;
195}
196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200198{
199 struct sk_buff *skb;
200 struct mgmt_hdr *hdr;
201 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300202 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Szymon Janc34eb5252011-02-28 14:10:08 +0100204 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205
Andre Guedes790eff42012-06-07 19:05:46 -0300206 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207 if (!skb)
208 return -ENOMEM;
209
210 hdr = (void *) skb_put(skb, sizeof(*hdr));
211
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530212 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100213 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214 hdr->len = cpu_to_le16(sizeof(*ev));
215
216 ev = (void *) skb_put(skb, sizeof(*ev));
217 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200218 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200219
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300220 err = sock_queue_rcv_skb(sk, skb);
221 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200222 kfree_skb(skb);
223
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300224 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200225}
226
Johan Hedbergaee9b212012-02-18 15:07:59 +0200227static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300228 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200229{
230 struct sk_buff *skb;
231 struct mgmt_hdr *hdr;
232 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200234
235 BT_DBG("sock %p", sk);
236
Andre Guedes790eff42012-06-07 19:05:46 -0300237 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200238 if (!skb)
239 return -ENOMEM;
240
241 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200242
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530243 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100244 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200248 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200249 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100250
251 if (rp)
252 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200253
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300254 err = sock_queue_rcv_skb(sk, skb);
255 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200256 kfree_skb(skb);
257
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100258 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200259}
260
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300261static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
262 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200263{
264 struct mgmt_rp_read_version rp;
265
266 BT_DBG("sock %p", sk);
267
268 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200269 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200270
Johan Hedbergaee9b212012-02-18 15:07:59 +0200271 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300272 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200273}
274
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300275static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
276 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200277{
278 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200279 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
280 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200281 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200282 size_t rp_size;
283 int i, err;
284
285 BT_DBG("sock %p", sk);
286
287 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
288
289 rp = kmalloc(rp_size, GFP_KERNEL);
290 if (!rp)
291 return -ENOMEM;
292
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200293 rp->num_commands = __constant_cpu_to_le16(num_commands);
294 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295
296 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
297 put_unaligned_le16(mgmt_commands[i], opcode);
298
299 for (i = 0; i < num_events; i++, opcode++)
300 put_unaligned_le16(mgmt_events[i], opcode);
301
Johan Hedbergaee9b212012-02-18 15:07:59 +0200302 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300303 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304 kfree(rp);
305
306 return err;
307}
308
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300309static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
310 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200313 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200314 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300316 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200317
318 BT_DBG("sock %p", sk);
319
320 read_lock(&hci_dev_list_lock);
321
322 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300323 list_for_each_entry(d, &hci_dev_list, list) {
324 if (!mgmt_valid_hdev(d))
325 continue;
326
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 count++;
328 }
329
Johan Hedberga38528f2011-01-22 06:46:43 +0200330 rp_len = sizeof(*rp) + (2 * count);
331 rp = kmalloc(rp_len, GFP_ATOMIC);
332 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100333 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200334 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100335 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200336
Johan Hedberg476e44c2012-10-19 20:10:46 +0300337 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200339 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200340 continue;
341
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700342 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
343 continue;
344
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300345 if (!mgmt_valid_hdev(d))
346 continue;
347
Johan Hedberg476e44c2012-10-19 20:10:46 +0300348 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 BT_DBG("Added hci%u", d->id);
350 }
351
Johan Hedberg476e44c2012-10-19 20:10:46 +0300352 rp->num_controllers = cpu_to_le16(count);
353 rp_len = sizeof(*rp) + (2 * count);
354
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b212012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Andre Guedes9a1a1992012-07-24 15:03:48 -0300372 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Andre Guedesed3fa312012-07-24 15:03:46 -0300375 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300376 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500377 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
378 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300379 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380 settings |= MGMT_SETTING_BREDR;
381 settings |= MGMT_SETTING_LINK_SECURITY;
382 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200383
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384 if (enable_hs)
385 settings |= MGMT_SETTING_HS;
386
Andre Guedesc383ddc2012-07-24 15:03:47 -0300387 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200388 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200389
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200390 return settings;
391}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200392
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200393static u32 get_current_settings(struct hci_dev *hdev)
394{
395 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200396
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200397 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 settings |= MGMT_SETTING_POWERED;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_CONNECTABLE;
402
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500403 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
404 settings |= MGMT_SETTING_FAST_CONNECTABLE;
405
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200406 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_DISCOVERABLE;
408
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200409 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_PAIRABLE;
411
Andre Guedesed3fa312012-07-24 15:03:46 -0300412 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_BREDR;
414
Johan Hedberg06199cf2012-02-22 16:37:11 +0200415 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200417
Johan Hedberg47990ea2012-02-22 11:58:37 +0200418 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200420
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200421 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200424 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
425 settings |= MGMT_SETTING_HS;
426
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200427 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200428}
429
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300430#define PNP_INFO_SVCLASS_ID 0x1200
431
Johan Hedberg213202e2013-01-27 00:31:33 +0200432static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
433{
434 u8 *ptr = data, *uuids_start = NULL;
435 struct bt_uuid *uuid;
436
437 if (len < 4)
438 return ptr;
439
440 list_for_each_entry(uuid, &hdev->uuids, list) {
441 u16 uuid16;
442
443 if (uuid->size != 16)
444 continue;
445
446 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
447 if (uuid16 < 0x1100)
448 continue;
449
450 if (uuid16 == PNP_INFO_SVCLASS_ID)
451 continue;
452
453 if (!uuids_start) {
454 uuids_start = ptr;
455 uuids_start[0] = 1;
456 uuids_start[1] = EIR_UUID16_ALL;
457 ptr += 2;
458 }
459
460 /* Stop if not enough space to put next UUID */
461 if ((ptr - data) + sizeof(u16) > len) {
462 uuids_start[1] = EIR_UUID16_SOME;
463 break;
464 }
465
466 *ptr++ = (uuid16 & 0x00ff);
467 *ptr++ = (uuid16 & 0xff00) >> 8;
468 uuids_start[0] += sizeof(uuid16);
469 }
470
471 return ptr;
472}
473
Johan Hedbergcdf19632013-01-27 00:31:34 +0200474static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
475{
476 u8 *ptr = data, *uuids_start = NULL;
477 struct bt_uuid *uuid;
478
479 if (len < 6)
480 return ptr;
481
482 list_for_each_entry(uuid, &hdev->uuids, list) {
483 if (uuid->size != 32)
484 continue;
485
486 if (!uuids_start) {
487 uuids_start = ptr;
488 uuids_start[0] = 1;
489 uuids_start[1] = EIR_UUID32_ALL;
490 ptr += 2;
491 }
492
493 /* Stop if not enough space to put next UUID */
494 if ((ptr - data) + sizeof(u32) > len) {
495 uuids_start[1] = EIR_UUID32_SOME;
496 break;
497 }
498
499 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
500 ptr += sizeof(u32);
501 uuids_start[0] += sizeof(u32);
502 }
503
504 return ptr;
505}
506
Johan Hedbergc00d5752013-01-27 00:31:35 +0200507static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
508{
509 u8 *ptr = data, *uuids_start = NULL;
510 struct bt_uuid *uuid;
511
512 if (len < 18)
513 return ptr;
514
515 list_for_each_entry(uuid, &hdev->uuids, list) {
516 if (uuid->size != 128)
517 continue;
518
519 if (!uuids_start) {
520 uuids_start = ptr;
521 uuids_start[0] = 1;
522 uuids_start[1] = EIR_UUID128_ALL;
523 ptr += 2;
524 }
525
526 /* Stop if not enough space to put next UUID */
527 if ((ptr - data) + 16 > len) {
528 uuids_start[1] = EIR_UUID128_SOME;
529 break;
530 }
531
532 memcpy(ptr, uuid->uuid, 16);
533 ptr += 16;
534 uuids_start[0] += 16;
535 }
536
537 return ptr;
538}
539
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300540static void create_eir(struct hci_dev *hdev, u8 *data)
541{
542 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300543 size_t name_len;
544
545 name_len = strlen(hdev->dev_name);
546
547 if (name_len > 0) {
548 /* EIR Data type */
549 if (name_len > 48) {
550 name_len = 48;
551 ptr[1] = EIR_NAME_SHORT;
552 } else
553 ptr[1] = EIR_NAME_COMPLETE;
554
555 /* EIR Data length */
556 ptr[0] = name_len + 1;
557
558 memcpy(ptr + 2, hdev->dev_name, name_len);
559
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300560 ptr += (name_len + 2);
561 }
562
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100563 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700564 ptr[0] = 2;
565 ptr[1] = EIR_TX_POWER;
566 ptr[2] = (u8) hdev->inq_tx_power;
567
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700568 ptr += 3;
569 }
570
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700571 if (hdev->devid_source > 0) {
572 ptr[0] = 9;
573 ptr[1] = EIR_DEVICE_ID;
574
575 put_unaligned_le16(hdev->devid_source, ptr + 2);
576 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
577 put_unaligned_le16(hdev->devid_product, ptr + 6);
578 put_unaligned_le16(hdev->devid_version, ptr + 8);
579
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700580 ptr += 10;
581 }
582
Johan Hedberg213202e2013-01-27 00:31:33 +0200583 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200584 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200585 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300586}
587
Johan Hedberg890ea892013-03-15 17:06:52 -0500588static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300589{
Johan Hedberg890ea892013-03-15 17:06:52 -0500590 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300591 struct hci_cp_write_eir cp;
592
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200593 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200595
Johan Hedberg976eb202012-10-24 21:12:01 +0300596 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500597 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300598
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200599 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200602 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500603 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300604
605 memset(&cp, 0, sizeof(cp));
606
607 create_eir(hdev, cp.data);
608
609 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500610 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300611
612 memcpy(hdev->eir, cp.data, sizeof(cp.data));
613
Johan Hedberg890ea892013-03-15 17:06:52 -0500614 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300615}
616
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200617static u8 get_service_classes(struct hci_dev *hdev)
618{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300619 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620 u8 val = 0;
621
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300622 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200623 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624
625 return val;
626}
627
Johan Hedberg890ea892013-03-15 17:06:52 -0500628static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200629{
Johan Hedberg890ea892013-03-15 17:06:52 -0500630 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200631 u8 cod[3];
632
633 BT_DBG("%s", hdev->name);
634
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200635 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500636 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200637
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200638 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500639 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200640
641 cod[0] = hdev->minor_class;
642 cod[1] = hdev->major_class;
643 cod[2] = get_service_classes(hdev);
644
645 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500646 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200647
Johan Hedberg890ea892013-03-15 17:06:52 -0500648 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200649}
650
Johan Hedberg7d785252011-12-15 00:47:39 +0200651static void service_cache_off(struct work_struct *work)
652{
653 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300654 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500655 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200656
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200657 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200658 return;
659
Johan Hedberg890ea892013-03-15 17:06:52 -0500660 hci_req_init(&req, hdev);
661
Johan Hedberg7d785252011-12-15 00:47:39 +0200662 hci_dev_lock(hdev);
663
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 update_eir(&req);
665 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200666
667 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500668
669 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200670}
671
Johan Hedberg6a919082012-02-28 06:17:26 +0200672static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200673{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200674 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200675 return;
676
Johan Hedberg4f87da82012-03-02 19:55:56 +0200677 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200678
Johan Hedberg4f87da82012-03-02 19:55:56 +0200679 /* Non-mgmt controlled devices get this bit set
680 * implicitly so that pairing works for them, however
681 * for mgmt we require user-space to explicitly enable
682 * it
683 */
684 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200685}
686
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200687static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300688 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200689{
690 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200691
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200692 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200693
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300694 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedberg03811012010-12-08 00:21:06 +0200696 memset(&rp, 0, sizeof(rp));
697
Johan Hedberg03811012010-12-08 00:21:06 +0200698 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200699
700 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200701 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200702
703 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
704 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
705
706 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200707
708 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200709 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200710
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300711 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200712
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200713 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300714 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200715}
716
717static void mgmt_pending_free(struct pending_cmd *cmd)
718{
719 sock_put(cmd->sk);
720 kfree(cmd->param);
721 kfree(cmd);
722}
723
724static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300725 struct hci_dev *hdev, void *data,
726 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200727{
728 struct pending_cmd *cmd;
729
Andre Guedes12b94562012-06-07 19:05:45 -0300730 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200731 if (!cmd)
732 return NULL;
733
734 cmd->opcode = opcode;
735 cmd->index = hdev->id;
736
Andre Guedes12b94562012-06-07 19:05:45 -0300737 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200738 if (!cmd->param) {
739 kfree(cmd);
740 return NULL;
741 }
742
743 if (data)
744 memcpy(cmd->param, data, len);
745
746 cmd->sk = sk;
747 sock_hold(sk);
748
749 list_add(&cmd->list, &hdev->mgmt_pending);
750
751 return cmd;
752}
753
754static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300755 void (*cb)(struct pending_cmd *cmd,
756 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300757 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200758{
Andre Guedesa3d09352013-02-01 11:21:30 -0300759 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200760
Andre Guedesa3d09352013-02-01 11:21:30 -0300761 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200762 if (opcode > 0 && cmd->opcode != opcode)
763 continue;
764
765 cb(cmd, data);
766 }
767}
768
769static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
770{
771 struct pending_cmd *cmd;
772
773 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
774 if (cmd->opcode == opcode)
775 return cmd;
776 }
777
778 return NULL;
779}
780
781static void mgmt_pending_remove(struct pending_cmd *cmd)
782{
783 list_del(&cmd->list);
784 mgmt_pending_free(cmd);
785}
786
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200788{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200789 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200790
Johan Hedbergaee9b212012-02-18 15:07:59 +0200791 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300792 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200793}
794
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200795static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300798 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200799 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200800 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200801
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200802 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200803
Johan Hedberga7e80f22013-01-09 16:05:19 +0200804 if (cp->val != 0x00 && cp->val != 0x01)
805 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
806 MGMT_STATUS_INVALID_PARAMS);
807
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300808 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200809
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300810 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
811 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
812 MGMT_STATUS_BUSY);
813 goto failed;
814 }
815
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100816 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
817 cancel_delayed_work(&hdev->power_off);
818
819 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200820 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
821 data, len);
822 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100823 goto failed;
824 }
825 }
826
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200827 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200828 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200829 goto failed;
830 }
831
Johan Hedberg03811012010-12-08 00:21:06 +0200832 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
833 if (!cmd) {
834 err = -ENOMEM;
835 goto failed;
836 }
837
838 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200839 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200840 else
Johan Hedberg19202572013-01-14 22:33:51 +0200841 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200842
843 err = 0;
844
845failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300846 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200847 return err;
848}
849
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300850static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
851 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200852{
853 struct sk_buff *skb;
854 struct mgmt_hdr *hdr;
855
Andre Guedes790eff42012-06-07 19:05:46 -0300856 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200857 if (!skb)
858 return -ENOMEM;
859
860 hdr = (void *) skb_put(skb, sizeof(*hdr));
861 hdr->opcode = cpu_to_le16(event);
862 if (hdev)
863 hdr->index = cpu_to_le16(hdev->id);
864 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530865 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200866 hdr->len = cpu_to_le16(data_len);
867
868 if (data)
869 memcpy(skb_put(skb, data_len), data, data_len);
870
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100871 /* Time stamp */
872 __net_timestamp(skb);
873
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200874 hci_send_to_control(skb, skip_sk);
875 kfree_skb(skb);
876
877 return 0;
878}
879
880static int new_settings(struct hci_dev *hdev, struct sock *skip)
881{
882 __le32 ev;
883
884 ev = cpu_to_le32(get_current_settings(hdev));
885
886 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
887}
888
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200889static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300890 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200891{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300892 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200893 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200894 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200895 u8 scan;
896 int err;
897
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200898 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200899
Johan Hedberg33c525c2012-10-24 21:11:58 +0300900 if (!lmp_bredr_capable(hdev))
901 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
902 MGMT_STATUS_NOT_SUPPORTED);
903
Johan Hedberga7e80f22013-01-09 16:05:19 +0200904 if (cp->val != 0x00 && cp->val != 0x01)
905 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
906 MGMT_STATUS_INVALID_PARAMS);
907
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700908 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100909 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200910 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300911 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200912
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300913 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200914
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200915 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200916 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300917 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200918 goto failed;
919 }
920
921 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300922 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200923 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300924 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200925 goto failed;
926 }
927
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200928 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200929 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300930 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200931 goto failed;
932 }
933
934 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200935 bool changed = false;
936
937 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
938 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
939 changed = true;
940 }
941
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200942 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200943 if (err < 0)
944 goto failed;
945
946 if (changed)
947 err = new_settings(hdev, sk);
948
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200949 goto failed;
950 }
951
952 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100953 if (hdev->discov_timeout > 0) {
954 cancel_delayed_work(&hdev->discov_off);
955 hdev->discov_timeout = 0;
956 }
957
958 if (cp->val && timeout > 0) {
959 hdev->discov_timeout = timeout;
960 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
961 msecs_to_jiffies(hdev->discov_timeout * 1000));
962 }
963
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200964 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200965 goto failed;
966 }
967
968 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
969 if (!cmd) {
970 err = -ENOMEM;
971 goto failed;
972 }
973
974 scan = SCAN_PAGE;
975
976 if (cp->val)
977 scan |= SCAN_INQUIRY;
978 else
979 cancel_delayed_work(&hdev->discov_off);
980
981 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
982 if (err < 0)
983 mgmt_pending_remove(cmd);
984
Johan Hedberg03811012010-12-08 00:21:06 +0200985 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200986 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200987
988failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300989 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200990 return err;
991}
992
Johan Hedberg406d7802013-03-15 17:07:09 -0500993static void write_fast_connectable(struct hci_request *req, bool enable)
994{
Johan Hedbergbd98b992013-03-15 17:07:13 -0500995 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -0500996 struct hci_cp_write_page_scan_activity acp;
997 u8 type;
998
Johan Hedberg4c01f8b2013-03-15 17:07:14 -0500999 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1000 return;
1001
Johan Hedberg406d7802013-03-15 17:07:09 -05001002 if (enable) {
1003 type = PAGE_SCAN_TYPE_INTERLACED;
1004
1005 /* 160 msec page scan interval */
1006 acp.interval = __constant_cpu_to_le16(0x0100);
1007 } else {
1008 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1009
1010 /* default 1.28 sec page scan */
1011 acp.interval = __constant_cpu_to_le16(0x0800);
1012 }
1013
1014 acp.window = __constant_cpu_to_le16(0x0012);
1015
Johan Hedbergbd98b992013-03-15 17:07:13 -05001016 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1017 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1018 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1019 sizeof(acp), &acp);
1020
1021 if (hdev->page_scan_type != type)
1022 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001023}
1024
Johan Hedberg2b76f452013-03-15 17:07:04 -05001025static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1026{
1027 struct pending_cmd *cmd;
1028
1029 BT_DBG("status 0x%02x", status);
1030
1031 hci_dev_lock(hdev);
1032
1033 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1034 if (!cmd)
1035 goto unlock;
1036
1037 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1038
1039 mgmt_pending_remove(cmd);
1040
1041unlock:
1042 hci_dev_unlock(hdev);
1043}
1044
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001045static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001046 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001047{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001048 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001049 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001050 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001051 u8 scan;
1052 int err;
1053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001054 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001055
Johan Hedberg33c525c2012-10-24 21:11:58 +03001056 if (!lmp_bredr_capable(hdev))
1057 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1058 MGMT_STATUS_NOT_SUPPORTED);
1059
Johan Hedberga7e80f22013-01-09 16:05:19 +02001060 if (cp->val != 0x00 && cp->val != 0x01)
1061 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1062 MGMT_STATUS_INVALID_PARAMS);
1063
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001064 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001065
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001066 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001067 bool changed = false;
1068
1069 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1070 changed = true;
1071
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001072 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001073 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001074 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001075 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1076 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1077 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001078
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001079 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001080 if (err < 0)
1081 goto failed;
1082
1083 if (changed)
1084 err = new_settings(hdev, sk);
1085
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001086 goto failed;
1087 }
1088
1089 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001090 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001091 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001092 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001093 goto failed;
1094 }
1095
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001096 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001097 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001098 goto failed;
1099 }
1100
1101 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1102 if (!cmd) {
1103 err = -ENOMEM;
1104 goto failed;
1105 }
1106
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001107 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001108 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001109 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001110 scan = 0;
1111
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001112 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001113 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001114 cancel_delayed_work(&hdev->discov_off);
1115 }
1116
Johan Hedberg2b76f452013-03-15 17:07:04 -05001117 hci_req_init(&req, hdev);
1118
1119 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1120
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001121 /* If we're going from non-connectable to connectable or
1122 * vice-versa when fast connectable is enabled ensure that fast
1123 * connectable gets disabled. write_fast_connectable won't do
1124 * anything if the page scan parameters are already what they
1125 * should be.
1126 */
1127 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001128 write_fast_connectable(&req, false);
1129
Johan Hedberg2b76f452013-03-15 17:07:04 -05001130 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001131 if (err < 0)
1132 mgmt_pending_remove(cmd);
1133
1134failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001135 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001136 return err;
1137}
1138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001139static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001140 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001142 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001143 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001144
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001145 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001146
Johan Hedberga7e80f22013-01-09 16:05:19 +02001147 if (cp->val != 0x00 && cp->val != 0x01)
1148 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1149 MGMT_STATUS_INVALID_PARAMS);
1150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001151 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001152
1153 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001154 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001155 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001156 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001157
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001158 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001159 if (err < 0)
1160 goto failed;
1161
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001162 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001163
1164failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001165 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166 return err;
1167}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001168
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001169static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1170 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001171{
1172 struct mgmt_mode *cp = data;
1173 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001174 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001175 int err;
1176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001177 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001178
Johan Hedberg33c525c2012-10-24 21:11:58 +03001179 if (!lmp_bredr_capable(hdev))
1180 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1181 MGMT_STATUS_NOT_SUPPORTED);
1182
Johan Hedberga7e80f22013-01-09 16:05:19 +02001183 if (cp->val != 0x00 && cp->val != 0x01)
1184 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1185 MGMT_STATUS_INVALID_PARAMS);
1186
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001187 hci_dev_lock(hdev);
1188
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001189 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001190 bool changed = false;
1191
1192 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001193 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001194 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1195 changed = true;
1196 }
1197
1198 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1199 if (err < 0)
1200 goto failed;
1201
1202 if (changed)
1203 err = new_settings(hdev, sk);
1204
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001205 goto failed;
1206 }
1207
1208 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001209 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001210 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001211 goto failed;
1212 }
1213
1214 val = !!cp->val;
1215
1216 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1217 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1218 goto failed;
1219 }
1220
1221 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1222 if (!cmd) {
1223 err = -ENOMEM;
1224 goto failed;
1225 }
1226
1227 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1228 if (err < 0) {
1229 mgmt_pending_remove(cmd);
1230 goto failed;
1231 }
1232
1233failed:
1234 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001235 return err;
1236}
1237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001238static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001239{
1240 struct mgmt_mode *cp = data;
1241 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001242 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001243 int err;
1244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001245 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001246
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001247 if (!lmp_ssp_capable(hdev))
1248 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1249 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001250
Johan Hedberga7e80f22013-01-09 16:05:19 +02001251 if (cp->val != 0x00 && cp->val != 0x01)
1252 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1253 MGMT_STATUS_INVALID_PARAMS);
1254
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001255 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001256
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001257 val = !!cp->val;
1258
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001259 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001260 bool changed = false;
1261
1262 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1263 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1264 changed = true;
1265 }
1266
1267 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1268 if (err < 0)
1269 goto failed;
1270
1271 if (changed)
1272 err = new_settings(hdev, sk);
1273
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001274 goto failed;
1275 }
1276
1277 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001278 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1279 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001280 goto failed;
1281 }
1282
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001283 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1284 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1285 goto failed;
1286 }
1287
1288 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1289 if (!cmd) {
1290 err = -ENOMEM;
1291 goto failed;
1292 }
1293
1294 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1295 if (err < 0) {
1296 mgmt_pending_remove(cmd);
1297 goto failed;
1298 }
1299
1300failed:
1301 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001302 return err;
1303}
1304
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001305static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001306{
1307 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001308
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001309 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001311 if (!enable_hs)
1312 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001313 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001314
Johan Hedberga7e80f22013-01-09 16:05:19 +02001315 if (cp->val != 0x00 && cp->val != 0x01)
1316 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1317 MGMT_STATUS_INVALID_PARAMS);
1318
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001319 if (cp->val)
1320 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1321 else
1322 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1323
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001324 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001325}
1326
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001327static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001328{
1329 struct mgmt_mode *cp = data;
1330 struct hci_cp_write_le_host_supported hci_cp;
1331 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001332 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001333 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001334
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001335 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001336
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001337 if (!lmp_le_capable(hdev))
1338 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1339 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001340
Johan Hedberga7e80f22013-01-09 16:05:19 +02001341 if (cp->val != 0x00 && cp->val != 0x01)
1342 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1343 MGMT_STATUS_INVALID_PARAMS);
1344
Johan Hedbergc73eee92013-04-19 18:35:21 +03001345 /* LE-only devices do not allow toggling LE on/off */
1346 if (!lmp_bredr_capable(hdev))
1347 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1348 MGMT_STATUS_REJECTED);
1349
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001350 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001351
1352 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001353 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001354
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001355 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001356 bool changed = false;
1357
1358 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1359 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1360 changed = true;
1361 }
1362
1363 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1364 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001365 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001366
1367 if (changed)
1368 err = new_settings(hdev, sk);
1369
Johan Hedberg1de028c2012-02-29 19:55:35 -08001370 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001371 }
1372
1373 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001374 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001375 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001376 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001377 }
1378
1379 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1380 if (!cmd) {
1381 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001382 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001383 }
1384
1385 memset(&hci_cp, 0, sizeof(hci_cp));
1386
1387 if (val) {
1388 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001389 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001390 }
1391
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001392 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1393 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301394 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001395 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001396
Johan Hedberg1de028c2012-02-29 19:55:35 -08001397unlock:
1398 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001399 return err;
1400}
1401
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001402/* This is a helper function to test for pending mgmt commands that can
1403 * cause CoD or EIR HCI commands. We can only allow one such pending
1404 * mgmt command at a time since otherwise we cannot easily track what
1405 * the current values are, will be, and based on that calculate if a new
1406 * HCI command needs to be sent and if yes with what value.
1407 */
1408static bool pending_eir_or_class(struct hci_dev *hdev)
1409{
1410 struct pending_cmd *cmd;
1411
1412 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1413 switch (cmd->opcode) {
1414 case MGMT_OP_ADD_UUID:
1415 case MGMT_OP_REMOVE_UUID:
1416 case MGMT_OP_SET_DEV_CLASS:
1417 case MGMT_OP_SET_POWERED:
1418 return true;
1419 }
1420 }
1421
1422 return false;
1423}
1424
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001425static const u8 bluetooth_base_uuid[] = {
1426 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1427 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1428};
1429
1430static u8 get_uuid_size(const u8 *uuid)
1431{
1432 u32 val;
1433
1434 if (memcmp(uuid, bluetooth_base_uuid, 12))
1435 return 128;
1436
1437 val = get_unaligned_le32(&uuid[12]);
1438 if (val > 0xffff)
1439 return 32;
1440
1441 return 16;
1442}
1443
Johan Hedberg92da6092013-03-15 17:06:55 -05001444static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1445{
1446 struct pending_cmd *cmd;
1447
1448 hci_dev_lock(hdev);
1449
1450 cmd = mgmt_pending_find(mgmt_op, hdev);
1451 if (!cmd)
1452 goto unlock;
1453
1454 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1455 hdev->dev_class, 3);
1456
1457 mgmt_pending_remove(cmd);
1458
1459unlock:
1460 hci_dev_unlock(hdev);
1461}
1462
1463static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1464{
1465 BT_DBG("status 0x%02x", status);
1466
1467 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1468}
1469
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001470static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001471{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001472 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001473 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001474 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001475 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001476 int err;
1477
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001478 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001479
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001480 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001481
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001482 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001483 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001484 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001485 goto failed;
1486 }
1487
Andre Guedes92c4c202012-06-07 19:05:44 -03001488 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001489 if (!uuid) {
1490 err = -ENOMEM;
1491 goto failed;
1492 }
1493
1494 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001495 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001496 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001497
Johan Hedbergde66aa62013-01-27 00:31:27 +02001498 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001499
Johan Hedberg890ea892013-03-15 17:06:52 -05001500 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001501
Johan Hedberg890ea892013-03-15 17:06:52 -05001502 update_class(&req);
1503 update_eir(&req);
1504
Johan Hedberg92da6092013-03-15 17:06:55 -05001505 err = hci_req_run(&req, add_uuid_complete);
1506 if (err < 0) {
1507 if (err != -ENODATA)
1508 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001509
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001510 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001511 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001512 goto failed;
1513 }
1514
1515 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001516 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001517 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001518 goto failed;
1519 }
1520
1521 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001522
1523failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001524 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001525 return err;
1526}
1527
Johan Hedberg24b78d02012-02-23 23:24:30 +02001528static bool enable_service_cache(struct hci_dev *hdev)
1529{
1530 if (!hdev_is_powered(hdev))
1531 return false;
1532
1533 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001534 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1535 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001536 return true;
1537 }
1538
1539 return false;
1540}
1541
Johan Hedberg92da6092013-03-15 17:06:55 -05001542static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1543{
1544 BT_DBG("status 0x%02x", status);
1545
1546 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1547}
1548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001550 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001551{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001552 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001553 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001554 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001555 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 -05001556 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001557 int err, found;
1558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001559 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001560
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001561 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001562
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001563 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001564 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001565 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001566 goto unlock;
1567 }
1568
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001569 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1570 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001571
Johan Hedberg24b78d02012-02-23 23:24:30 +02001572 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001573 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001574 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001575 goto unlock;
1576 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001577
Johan Hedberg9246a862012-02-23 21:33:16 +02001578 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001579 }
1580
1581 found = 0;
1582
Johan Hedberg056341c2013-01-27 00:31:30 +02001583 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001584 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1585 continue;
1586
1587 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001588 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001589 found++;
1590 }
1591
1592 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001593 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001594 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001595 goto unlock;
1596 }
1597
Johan Hedberg9246a862012-02-23 21:33:16 +02001598update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001599 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001600
Johan Hedberg890ea892013-03-15 17:06:52 -05001601 update_class(&req);
1602 update_eir(&req);
1603
Johan Hedberg92da6092013-03-15 17:06:55 -05001604 err = hci_req_run(&req, remove_uuid_complete);
1605 if (err < 0) {
1606 if (err != -ENODATA)
1607 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001608
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001609 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001610 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001611 goto unlock;
1612 }
1613
1614 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001615 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001616 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001617 goto unlock;
1618 }
1619
1620 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001621
1622unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001623 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001624 return err;
1625}
1626
Johan Hedberg92da6092013-03-15 17:06:55 -05001627static void set_class_complete(struct hci_dev *hdev, u8 status)
1628{
1629 BT_DBG("status 0x%02x", status);
1630
1631 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1632}
1633
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001634static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001635 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001636{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001637 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001638 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001639 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001640 int err;
1641
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001642 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001643
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001644 if (!lmp_bredr_capable(hdev))
1645 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1646 MGMT_STATUS_NOT_SUPPORTED);
1647
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001648 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001649
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001650 if (pending_eir_or_class(hdev)) {
1651 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1652 MGMT_STATUS_BUSY);
1653 goto unlock;
1654 }
1655
1656 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1657 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1658 MGMT_STATUS_INVALID_PARAMS);
1659 goto unlock;
1660 }
1661
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001662 hdev->major_class = cp->major;
1663 hdev->minor_class = cp->minor;
1664
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001665 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001666 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001667 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001668 goto unlock;
1669 }
1670
Johan Hedberg890ea892013-03-15 17:06:52 -05001671 hci_req_init(&req, hdev);
1672
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001673 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001674 hci_dev_unlock(hdev);
1675 cancel_delayed_work_sync(&hdev->service_cache);
1676 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001677 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001678 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001679
Johan Hedberg890ea892013-03-15 17:06:52 -05001680 update_class(&req);
1681
Johan Hedberg92da6092013-03-15 17:06:55 -05001682 err = hci_req_run(&req, set_class_complete);
1683 if (err < 0) {
1684 if (err != -ENODATA)
1685 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001686
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001687 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001688 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001689 goto unlock;
1690 }
1691
1692 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001693 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001694 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001695 goto unlock;
1696 }
1697
1698 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001699
Johan Hedbergb5235a62012-02-21 14:32:24 +02001700unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001701 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001702 return err;
1703}
1704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001705static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001706 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001707{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001708 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001709 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001710 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001711
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001712 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001713
Johan Hedberg86742e12011-11-07 23:13:38 +02001714 expected_len = sizeof(*cp) + key_count *
1715 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001716 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001717 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001718 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001719 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001720 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001721 }
1722
Johan Hedberg4ae14302013-01-20 14:27:13 +02001723 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1724 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1725 MGMT_STATUS_INVALID_PARAMS);
1726
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001727 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001728 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001729
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001730 for (i = 0; i < key_count; i++) {
1731 struct mgmt_link_key_info *key = &cp->keys[i];
1732
1733 if (key->addr.type != BDADDR_BREDR)
1734 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1735 MGMT_STATUS_INVALID_PARAMS);
1736 }
1737
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001738 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001739
1740 hci_link_keys_clear(hdev);
1741
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001742 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001743 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001744 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001745 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001746
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001747 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001748 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001749
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001750 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001751 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001752 }
1753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001754 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001755
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001756 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001757
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001758 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001759}
1760
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001761static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001762 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001763{
1764 struct mgmt_ev_device_unpaired ev;
1765
1766 bacpy(&ev.addr.bdaddr, bdaddr);
1767 ev.addr.type = addr_type;
1768
1769 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001770 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001771}
1772
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001773static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001774 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001775{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001776 struct mgmt_cp_unpair_device *cp = data;
1777 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001778 struct hci_cp_disconnect dc;
1779 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001780 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001781 int err;
1782
Johan Hedberga8a1d192011-11-10 15:54:38 +02001783 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001784 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1785 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001786
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001787 if (!bdaddr_type_is_valid(cp->addr.type))
1788 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1789 MGMT_STATUS_INVALID_PARAMS,
1790 &rp, sizeof(rp));
1791
Johan Hedberg118da702013-01-20 14:27:20 +02001792 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1793 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1794 MGMT_STATUS_INVALID_PARAMS,
1795 &rp, sizeof(rp));
1796
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001797 hci_dev_lock(hdev);
1798
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001799 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001800 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001801 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001802 goto unlock;
1803 }
1804
Andre Guedes591f47f2012-04-24 21:02:49 -03001805 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001806 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1807 else
1808 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001809
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001810 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001812 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001813 goto unlock;
1814 }
1815
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001816 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001817 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001818 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001819 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001820 else
1821 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001822 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001823 } else {
1824 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001825 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001826
Johan Hedberga8a1d192011-11-10 15:54:38 +02001827 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001828 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001829 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001830 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001831 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001832 }
1833
Johan Hedberg124f6e32012-02-09 13:50:12 +02001834 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001835 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001836 if (!cmd) {
1837 err = -ENOMEM;
1838 goto unlock;
1839 }
1840
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001841 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001842 dc.reason = 0x13; /* Remote User Terminated Connection */
1843 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1844 if (err < 0)
1845 mgmt_pending_remove(cmd);
1846
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001847unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001848 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001849 return err;
1850}
1851
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001852static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001853 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001854{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001855 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001856 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001857 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001858 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001859 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001860 int err;
1861
1862 BT_DBG("");
1863
Johan Hedberg06a63b12013-01-20 14:27:21 +02001864 memset(&rp, 0, sizeof(rp));
1865 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1866 rp.addr.type = cp->addr.type;
1867
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001868 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001869 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1870 MGMT_STATUS_INVALID_PARAMS,
1871 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001872
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001873 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001874
1875 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001876 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1877 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001878 goto failed;
1879 }
1880
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001881 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001882 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1883 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001884 goto failed;
1885 }
1886
Andre Guedes591f47f2012-04-24 21:02:49 -03001887 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001888 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1889 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001890 else
1891 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001892
Vishal Agarwalf9607272012-06-13 05:32:43 +05301893 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001894 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1895 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001896 goto failed;
1897 }
1898
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001899 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001900 if (!cmd) {
1901 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001902 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001903 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001904
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001905 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001906 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001907
1908 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1909 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001910 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001911
1912failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001913 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001914 return err;
1915}
1916
Andre Guedes57c14772012-04-24 21:02:50 -03001917static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001918{
1919 switch (link_type) {
1920 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001921 switch (addr_type) {
1922 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001923 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001924
Johan Hedberg48264f02011-11-09 13:58:58 +02001925 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001926 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001927 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001928 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001929
Johan Hedberg4c659c32011-11-07 23:13:39 +02001930 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001931 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001932 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001933 }
1934}
1935
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001936static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1937 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001938{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001939 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001940 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001941 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001942 int err;
1943 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001944
1945 BT_DBG("");
1946
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001947 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001948
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001949 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001950 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001951 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001952 goto unlock;
1953 }
1954
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001955 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001956 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1957 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001958 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001959 }
1960
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001961 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001962 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001963 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001964 err = -ENOMEM;
1965 goto unlock;
1966 }
1967
Johan Hedberg2784eb42011-01-21 13:56:35 +02001968 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001969 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001970 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1971 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001972 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001973 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001974 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001975 continue;
1976 i++;
1977 }
1978
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001979 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001980
Johan Hedberg4c659c32011-11-07 23:13:39 +02001981 /* Recalculate length in case of filtered SCO connections, etc */
1982 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001983
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001985 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001986
Johan Hedberga38528f2011-01-22 06:46:43 +02001987 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001988
1989unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001990 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001991 return err;
1992}
1993
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001994static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001995 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001996{
1997 struct pending_cmd *cmd;
1998 int err;
1999
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002000 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002001 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002002 if (!cmd)
2003 return -ENOMEM;
2004
Johan Hedbergd8457692012-02-17 14:24:57 +02002005 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002006 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002007 if (err < 0)
2008 mgmt_pending_remove(cmd);
2009
2010 return err;
2011}
2012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002013static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002014 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002015{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002016 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002017 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002018 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002019 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002020 int err;
2021
2022 BT_DBG("");
2023
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002024 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002025
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002026 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002027 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002028 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002029 goto failed;
2030 }
2031
Johan Hedbergd8457692012-02-17 14:24:57 +02002032 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002033 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002034 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002035 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002036 goto failed;
2037 }
2038
2039 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002040 struct mgmt_cp_pin_code_neg_reply ncp;
2041
2042 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002043
2044 BT_ERR("PIN code is not 16 bytes long");
2045
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002046 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002047 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002048 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002049 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002050
2051 goto failed;
2052 }
2053
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002054 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002055 if (!cmd) {
2056 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002057 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002058 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002059
Johan Hedbergd8457692012-02-17 14:24:57 +02002060 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002061 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002062 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002063
2064 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2065 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002066 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002067
2068failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002069 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002070 return err;
2071}
2072
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002073static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2074 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002075{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002076 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002077
2078 BT_DBG("");
2079
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002080 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002081
2082 hdev->io_capability = cp->io_capability;
2083
2084 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002085 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002086
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002087 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002088
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002089 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2090 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002091}
2092
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002093static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002094{
2095 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002096 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002097
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002098 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002099 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2100 continue;
2101
Johan Hedberge9a416b2011-02-19 12:05:56 -03002102 if (cmd->user_data != conn)
2103 continue;
2104
2105 return cmd;
2106 }
2107
2108 return NULL;
2109}
2110
2111static void pairing_complete(struct pending_cmd *cmd, u8 status)
2112{
2113 struct mgmt_rp_pair_device rp;
2114 struct hci_conn *conn = cmd->user_data;
2115
Johan Hedbergba4e5642011-11-11 00:07:34 +02002116 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002117 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002118
Johan Hedbergaee9b212012-02-18 15:07:59 +02002119 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002120 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002121
2122 /* So we don't get further callbacks for this connection */
2123 conn->connect_cfm_cb = NULL;
2124 conn->security_cfm_cb = NULL;
2125 conn->disconn_cfm_cb = NULL;
2126
David Herrmann76a68ba2013-04-06 20:28:37 +02002127 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002128
Johan Hedberga664b5b2011-02-19 12:06:02 -03002129 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002130}
2131
2132static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2133{
2134 struct pending_cmd *cmd;
2135
2136 BT_DBG("status %u", status);
2137
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002138 cmd = find_pairing(conn);
2139 if (!cmd)
2140 BT_DBG("Unable to find a pending command");
2141 else
Johan Hedberge2113262012-02-18 15:20:03 +02002142 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002143}
2144
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302145static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2146{
2147 struct pending_cmd *cmd;
2148
2149 BT_DBG("status %u", status);
2150
2151 if (!status)
2152 return;
2153
2154 cmd = find_pairing(conn);
2155 if (!cmd)
2156 BT_DBG("Unable to find a pending command");
2157 else
2158 pairing_complete(cmd, mgmt_status(status));
2159}
2160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002161static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002162 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002163{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002164 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002165 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002166 struct pending_cmd *cmd;
2167 u8 sec_level, auth_type;
2168 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002169 int err;
2170
2171 BT_DBG("");
2172
Szymon Jancf950a30e2013-01-18 12:48:07 +01002173 memset(&rp, 0, sizeof(rp));
2174 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2175 rp.addr.type = cp->addr.type;
2176
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002177 if (!bdaddr_type_is_valid(cp->addr.type))
2178 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2179 MGMT_STATUS_INVALID_PARAMS,
2180 &rp, sizeof(rp));
2181
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002182 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002183
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002184 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002185 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2186 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002187 goto unlock;
2188 }
2189
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002190 sec_level = BT_SECURITY_MEDIUM;
2191 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002192 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002193 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002194 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002195
Andre Guedes591f47f2012-04-24 21:02:49 -03002196 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002197 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2198 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002199 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002200 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2201 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002202
Ville Tervo30e76272011-02-22 16:10:53 -03002203 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002204 int status;
2205
2206 if (PTR_ERR(conn) == -EBUSY)
2207 status = MGMT_STATUS_BUSY;
2208 else
2209 status = MGMT_STATUS_CONNECT_FAILED;
2210
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002211 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002212 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002213 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002214 goto unlock;
2215 }
2216
2217 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002218 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002219 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002220 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002221 goto unlock;
2222 }
2223
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002224 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002225 if (!cmd) {
2226 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002227 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002228 goto unlock;
2229 }
2230
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002231 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002232 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002233 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302234 else
2235 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002236
Johan Hedberge9a416b2011-02-19 12:05:56 -03002237 conn->security_cfm_cb = pairing_complete_cb;
2238 conn->disconn_cfm_cb = pairing_complete_cb;
2239 conn->io_capability = cp->io_cap;
2240 cmd->user_data = conn;
2241
2242 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002243 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002244 pairing_complete(cmd, 0);
2245
2246 err = 0;
2247
2248unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002250 return err;
2251}
2252
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002253static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2254 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002255{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002256 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002257 struct pending_cmd *cmd;
2258 struct hci_conn *conn;
2259 int err;
2260
2261 BT_DBG("");
2262
Johan Hedberg28424702012-02-02 04:02:29 +02002263 hci_dev_lock(hdev);
2264
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002265 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002266 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002267 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002268 goto unlock;
2269 }
2270
Johan Hedberg28424702012-02-02 04:02:29 +02002271 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2272 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002273 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002274 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002275 goto unlock;
2276 }
2277
2278 conn = cmd->user_data;
2279
2280 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002281 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002282 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002283 goto unlock;
2284 }
2285
2286 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2287
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002288 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002289 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002290unlock:
2291 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002292 return err;
2293}
2294
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002295static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002296 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002297 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002298{
Johan Hedberga5c29682011-02-19 12:05:57 -03002299 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002300 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002301 int err;
2302
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002303 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002304
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002305 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002306 err = cmd_complete(sk, hdev->id, mgmt_op,
2307 MGMT_STATUS_NOT_POWERED, addr,
2308 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002309 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002310 }
2311
Johan Hedberg1707c602013-03-15 17:07:15 -05002312 if (addr->type == BDADDR_BREDR)
2313 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002314 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002315 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002316
Johan Hedberg272d90d2012-02-09 15:26:12 +02002317 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002318 err = cmd_complete(sk, hdev->id, mgmt_op,
2319 MGMT_STATUS_NOT_CONNECTED, addr,
2320 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002321 goto done;
2322 }
2323
Johan Hedberg1707c602013-03-15 17:07:15 -05002324 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002325 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002326 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002327
Brian Gix5fe57d92011-12-21 16:12:13 -08002328 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002329 err = cmd_complete(sk, hdev->id, mgmt_op,
2330 MGMT_STATUS_SUCCESS, addr,
2331 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002332 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002333 err = cmd_complete(sk, hdev->id, mgmt_op,
2334 MGMT_STATUS_FAILED, addr,
2335 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002336
Brian Gix47c15e22011-11-16 13:53:14 -08002337 goto done;
2338 }
2339
Johan Hedberg1707c602013-03-15 17:07:15 -05002340 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002341 if (!cmd) {
2342 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002343 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002344 }
2345
Brian Gix0df4c182011-11-16 13:53:13 -08002346 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002347 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2348 struct hci_cp_user_passkey_reply cp;
2349
Johan Hedberg1707c602013-03-15 17:07:15 -05002350 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002351 cp.passkey = passkey;
2352 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2353 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002354 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2355 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002356
Johan Hedberga664b5b2011-02-19 12:06:02 -03002357 if (err < 0)
2358 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002359
Brian Gix0df4c182011-11-16 13:53:13 -08002360done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002362 return err;
2363}
2364
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302365static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2366 void *data, u16 len)
2367{
2368 struct mgmt_cp_pin_code_neg_reply *cp = data;
2369
2370 BT_DBG("");
2371
Johan Hedberg1707c602013-03-15 17:07:15 -05002372 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302373 MGMT_OP_PIN_CODE_NEG_REPLY,
2374 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2375}
2376
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002377static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2378 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002379{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002380 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002381
2382 BT_DBG("");
2383
2384 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002385 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002386 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002387
Johan Hedberg1707c602013-03-15 17:07:15 -05002388 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002389 MGMT_OP_USER_CONFIRM_REPLY,
2390 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002391}
2392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002393static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002394 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002395{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002396 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002397
2398 BT_DBG("");
2399
Johan Hedberg1707c602013-03-15 17:07:15 -05002400 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002401 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2402 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002403}
2404
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002405static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2406 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002407{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002408 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002409
2410 BT_DBG("");
2411
Johan Hedberg1707c602013-03-15 17:07:15 -05002412 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002413 MGMT_OP_USER_PASSKEY_REPLY,
2414 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002415}
2416
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002417static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002418 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002419{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002420 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002421
2422 BT_DBG("");
2423
Johan Hedberg1707c602013-03-15 17:07:15 -05002424 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002425 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2426 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002427}
2428
Johan Hedberg13928972013-03-15 17:07:00 -05002429static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002430{
Johan Hedberg13928972013-03-15 17:07:00 -05002431 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002432 struct hci_cp_write_local_name cp;
2433
Johan Hedberg13928972013-03-15 17:07:00 -05002434 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002435
Johan Hedberg890ea892013-03-15 17:06:52 -05002436 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002437}
2438
Johan Hedberg13928972013-03-15 17:07:00 -05002439static void set_name_complete(struct hci_dev *hdev, u8 status)
2440{
2441 struct mgmt_cp_set_local_name *cp;
2442 struct pending_cmd *cmd;
2443
2444 BT_DBG("status 0x%02x", status);
2445
2446 hci_dev_lock(hdev);
2447
2448 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2449 if (!cmd)
2450 goto unlock;
2451
2452 cp = cmd->param;
2453
2454 if (status)
2455 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2456 mgmt_status(status));
2457 else
2458 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2459 cp, sizeof(*cp));
2460
2461 mgmt_pending_remove(cmd);
2462
2463unlock:
2464 hci_dev_unlock(hdev);
2465}
2466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002467static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002468 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002469{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002470 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002471 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002472 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002473 int err;
2474
2475 BT_DBG("");
2476
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002477 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002478
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002479 /* If the old values are the same as the new ones just return a
2480 * direct command complete event.
2481 */
2482 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2483 !memcmp(hdev->short_name, cp->short_name,
2484 sizeof(hdev->short_name))) {
2485 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2486 data, len);
2487 goto failed;
2488 }
2489
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002490 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002491
Johan Hedbergb5235a62012-02-21 14:32:24 +02002492 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002493 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002494
2495 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002496 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002497 if (err < 0)
2498 goto failed;
2499
2500 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002501 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002502
Johan Hedbergb5235a62012-02-21 14:32:24 +02002503 goto failed;
2504 }
2505
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002506 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002507 if (!cmd) {
2508 err = -ENOMEM;
2509 goto failed;
2510 }
2511
Johan Hedberg13928972013-03-15 17:07:00 -05002512 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2513
Johan Hedberg890ea892013-03-15 17:06:52 -05002514 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002515
2516 if (lmp_bredr_capable(hdev)) {
2517 update_name(&req);
2518 update_eir(&req);
2519 }
2520
2521 if (lmp_le_capable(hdev))
2522 hci_update_ad(&req);
2523
Johan Hedberg13928972013-03-15 17:07:00 -05002524 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002525 if (err < 0)
2526 mgmt_pending_remove(cmd);
2527
2528failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002529 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002530 return err;
2531}
2532
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002533static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002534 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002535{
Szymon Jancc35938b2011-03-22 13:12:21 +01002536 struct pending_cmd *cmd;
2537 int err;
2538
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002539 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002540
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002541 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002542
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002543 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002544 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002545 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002546 goto unlock;
2547 }
2548
Andre Guedes9a1a1992012-07-24 15:03:48 -03002549 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002550 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002551 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002552 goto unlock;
2553 }
2554
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002555 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002556 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002557 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002558 goto unlock;
2559 }
2560
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002561 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002562 if (!cmd) {
2563 err = -ENOMEM;
2564 goto unlock;
2565 }
2566
2567 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2568 if (err < 0)
2569 mgmt_pending_remove(cmd);
2570
2571unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002572 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002573 return err;
2574}
2575
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002576static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002577 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002578{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002579 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002580 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002581 int err;
2582
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002583 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002584
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002585 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002586
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002587 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002589 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002590 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002591 else
Szymon Janca6785be2012-12-13 15:11:21 +01002592 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002594 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002595 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002597 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002598 return err;
2599}
2600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002601static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002602 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002603{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002604 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002605 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002606 int err;
2607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002608 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002609
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002610 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002611
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002612 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002613 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002614 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002615 else
Szymon Janca6785be2012-12-13 15:11:21 +01002616 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002617
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002619 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002620
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002621 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002622 return err;
2623}
2624
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002625static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2626{
2627 struct pending_cmd *cmd;
2628 u8 type;
2629 int err;
2630
2631 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2632
2633 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2634 if (!cmd)
2635 return -ENOENT;
2636
2637 type = hdev->discovery.type;
2638
2639 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2640 &type, sizeof(type));
2641 mgmt_pending_remove(cmd);
2642
2643 return err;
2644}
2645
Andre Guedes7c307722013-04-30 15:29:28 -03002646static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2647{
2648 BT_DBG("status %d", status);
2649
2650 if (status) {
2651 hci_dev_lock(hdev);
2652 mgmt_start_discovery_failed(hdev, status);
2653 hci_dev_unlock(hdev);
2654 return;
2655 }
2656
2657 hci_dev_lock(hdev);
2658 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2659 hci_dev_unlock(hdev);
2660
2661 switch (hdev->discovery.type) {
2662 case DISCOV_TYPE_LE:
2663 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002664 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002665 break;
2666
2667 case DISCOV_TYPE_INTERLEAVED:
2668 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002669 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002670 break;
2671
2672 case DISCOV_TYPE_BREDR:
2673 break;
2674
2675 default:
2676 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2677 }
2678}
2679
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002680static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002681 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002682{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002683 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002684 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002685 struct hci_cp_le_set_scan_param param_cp;
2686 struct hci_cp_le_set_scan_enable enable_cp;
2687 struct hci_cp_inquiry inq_cp;
2688 struct hci_request req;
2689 /* General inquiry access code (GIAC) */
2690 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002691 int err;
2692
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002693 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002694
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002695 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002696
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002697 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002700 goto failed;
2701 }
2702
Andre Guedes642be6c2012-03-21 00:03:37 -03002703 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2704 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2705 MGMT_STATUS_BUSY);
2706 goto failed;
2707 }
2708
Johan Hedbergff9ef572012-01-04 14:23:45 +02002709 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002712 goto failed;
2713 }
2714
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002715 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002716 if (!cmd) {
2717 err = -ENOMEM;
2718 goto failed;
2719 }
2720
Andre Guedes4aab14e2012-02-17 20:39:36 -03002721 hdev->discovery.type = cp->type;
2722
Andre Guedes7c307722013-04-30 15:29:28 -03002723 hci_req_init(&req, hdev);
2724
Andre Guedes4aab14e2012-02-17 20:39:36 -03002725 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002726 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002727 if (!lmp_bredr_capable(hdev)) {
2728 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2729 MGMT_STATUS_NOT_SUPPORTED);
2730 mgmt_pending_remove(cmd);
2731 goto failed;
2732 }
2733
Andre Guedes7c307722013-04-30 15:29:28 -03002734 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2735 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2736 MGMT_STATUS_BUSY);
2737 mgmt_pending_remove(cmd);
2738 goto failed;
2739 }
2740
2741 hci_inquiry_cache_flush(hdev);
2742
2743 memset(&inq_cp, 0, sizeof(inq_cp));
2744 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002745 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002746 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002747 break;
2748
2749 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002750 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002751 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002752 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2753 MGMT_STATUS_NOT_SUPPORTED);
2754 mgmt_pending_remove(cmd);
2755 goto failed;
2756 }
2757
Andre Guedes7c307722013-04-30 15:29:28 -03002758 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
2759 !lmp_bredr_capable(hdev)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002760 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2761 MGMT_STATUS_NOT_SUPPORTED);
2762 mgmt_pending_remove(cmd);
2763 goto failed;
2764 }
2765
Andre Guedes7c307722013-04-30 15:29:28 -03002766 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2767 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2768 MGMT_STATUS_REJECTED);
2769 mgmt_pending_remove(cmd);
2770 goto failed;
2771 }
2772
2773 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2774 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2775 MGMT_STATUS_BUSY);
2776 mgmt_pending_remove(cmd);
2777 goto failed;
2778 }
2779
2780 memset(&param_cp, 0, sizeof(param_cp));
2781 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002782 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2783 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002784 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2785 &param_cp);
2786
2787 memset(&enable_cp, 0, sizeof(enable_cp));
2788 enable_cp.enable = LE_SCAN_ENABLE;
2789 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2790 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2791 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002792 break;
2793
Andre Guedesf39799f2012-02-17 20:39:35 -03002794 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002795 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2796 MGMT_STATUS_INVALID_PARAMS);
2797 mgmt_pending_remove(cmd);
2798 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002799 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002800
Andre Guedes7c307722013-04-30 15:29:28 -03002801 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002802 if (err < 0)
2803 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002804 else
2805 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002806
2807failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002808 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002809 return err;
2810}
2811
Andre Guedes1183fdc2013-04-30 15:29:35 -03002812static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2813{
2814 struct pending_cmd *cmd;
2815 int err;
2816
2817 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2818 if (!cmd)
2819 return -ENOENT;
2820
2821 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2822 &hdev->discovery.type, sizeof(hdev->discovery.type));
2823 mgmt_pending_remove(cmd);
2824
2825 return err;
2826}
2827
Andre Guedes0e05bba2013-04-30 15:29:33 -03002828static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2829{
2830 BT_DBG("status %d", status);
2831
2832 hci_dev_lock(hdev);
2833
2834 if (status) {
2835 mgmt_stop_discovery_failed(hdev, status);
2836 goto unlock;
2837 }
2838
2839 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2840
2841unlock:
2842 hci_dev_unlock(hdev);
2843}
2844
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002845static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002846 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002847{
Johan Hedbergd9306502012-02-20 23:25:18 +02002848 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002849 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002850 struct hci_cp_remote_name_req_cancel cp;
2851 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002852 struct hci_request req;
2853 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002854 int err;
2855
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002856 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002858 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002859
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002860 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002861 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002862 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2863 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002864 goto unlock;
2865 }
2866
2867 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002868 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002869 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2870 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002871 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002872 }
2873
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002874 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002875 if (!cmd) {
2876 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002877 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002878 }
2879
Andre Guedes0e05bba2013-04-30 15:29:33 -03002880 hci_req_init(&req, hdev);
2881
Andre Guedese0d9727e2012-03-20 15:15:36 -03002882 switch (hdev->discovery.state) {
2883 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002884 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2885 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2886 } else {
2887 cancel_delayed_work(&hdev->le_scan_disable);
2888
2889 memset(&enable_cp, 0, sizeof(enable_cp));
2890 enable_cp.enable = LE_SCAN_DISABLE;
2891 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2892 sizeof(enable_cp), &enable_cp);
2893 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002894
Andre Guedese0d9727e2012-03-20 15:15:36 -03002895 break;
2896
2897 case DISCOVERY_RESOLVING:
2898 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002899 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002900 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002901 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002902 err = cmd_complete(sk, hdev->id,
2903 MGMT_OP_STOP_DISCOVERY, 0,
2904 &mgmt_cp->type,
2905 sizeof(mgmt_cp->type));
2906 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2907 goto unlock;
2908 }
2909
2910 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002911 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2912 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002913
2914 break;
2915
2916 default:
2917 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002918
2919 mgmt_pending_remove(cmd);
2920 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
2921 MGMT_STATUS_FAILED, &mgmt_cp->type,
2922 sizeof(mgmt_cp->type));
2923 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002924 }
2925
Andre Guedes0e05bba2013-04-30 15:29:33 -03002926 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002927 if (err < 0)
2928 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002929 else
2930 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002931
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002932unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002933 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002934 return err;
2935}
2936
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002937static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002938 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002939{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002940 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002941 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002942 int err;
2943
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002944 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002945
Johan Hedberg561aafb2012-01-04 13:31:59 +02002946 hci_dev_lock(hdev);
2947
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002948 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002949 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002950 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002951 goto failed;
2952 }
2953
Johan Hedberga198e7b2012-02-17 14:27:06 +02002954 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002955 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002956 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002958 goto failed;
2959 }
2960
2961 if (cp->name_known) {
2962 e->name_state = NAME_KNOWN;
2963 list_del(&e->list);
2964 } else {
2965 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002966 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002967 }
2968
Johan Hedberge3846622013-01-09 15:29:33 +02002969 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
2970 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02002971
2972failed:
2973 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002974 return err;
2975}
2976
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002977static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002978 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002979{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002980 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002981 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002982 int err;
2983
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002984 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002985
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002986 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002987 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
2988 MGMT_STATUS_INVALID_PARAMS,
2989 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002990
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002991 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002992
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002993 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002994 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002995 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002996 else
Szymon Janca6785be2012-12-13 15:11:21 +01002997 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002998
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002999 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003000 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003002 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003003
3004 return err;
3005}
3006
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003007static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003008 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003009{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003010 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003011 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003012 int err;
3013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003014 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003015
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003016 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003017 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3018 MGMT_STATUS_INVALID_PARAMS,
3019 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003020
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003021 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003022
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003023 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003024 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003025 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003026 else
Szymon Janca6785be2012-12-13 15:11:21 +01003027 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003028
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003029 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003030 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003031
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003032 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003033
3034 return err;
3035}
3036
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003037static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3038 u16 len)
3039{
3040 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003041 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003042 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003043 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003044
3045 BT_DBG("%s", hdev->name);
3046
Szymon Jancc72d4b82012-03-16 16:02:57 +01003047 source = __le16_to_cpu(cp->source);
3048
3049 if (source > 0x0002)
3050 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3051 MGMT_STATUS_INVALID_PARAMS);
3052
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003053 hci_dev_lock(hdev);
3054
Szymon Jancc72d4b82012-03-16 16:02:57 +01003055 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003056 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3057 hdev->devid_product = __le16_to_cpu(cp->product);
3058 hdev->devid_version = __le16_to_cpu(cp->version);
3059
3060 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3061
Johan Hedberg890ea892013-03-15 17:06:52 -05003062 hci_req_init(&req, hdev);
3063 update_eir(&req);
3064 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003065
3066 hci_dev_unlock(hdev);
3067
3068 return err;
3069}
3070
Johan Hedberg33e38b32013-03-15 17:07:05 -05003071static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3072{
3073 struct pending_cmd *cmd;
3074
3075 BT_DBG("status 0x%02x", status);
3076
3077 hci_dev_lock(hdev);
3078
3079 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3080 if (!cmd)
3081 goto unlock;
3082
3083 if (status) {
3084 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3085 mgmt_status(status));
3086 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003087 struct mgmt_mode *cp = cmd->param;
3088
3089 if (cp->val)
3090 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3091 else
3092 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3093
Johan Hedberg33e38b32013-03-15 17:07:05 -05003094 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3095 new_settings(hdev, cmd->sk);
3096 }
3097
3098 mgmt_pending_remove(cmd);
3099
3100unlock:
3101 hci_dev_unlock(hdev);
3102}
3103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003104static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003106{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003107 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003108 struct pending_cmd *cmd;
3109 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003110 int err;
3111
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003112 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003113
Johan Hedberg1a47aee2013-03-15 17:07:06 -05003114 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003115 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3116 MGMT_STATUS_NOT_SUPPORTED);
3117
Johan Hedberga7e80f22013-01-09 16:05:19 +02003118 if (cp->val != 0x00 && cp->val != 0x01)
3119 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3120 MGMT_STATUS_INVALID_PARAMS);
3121
Johan Hedberg5400c042012-02-21 16:40:33 +02003122 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003123 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003124 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003125
3126 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003127 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003128 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003129
3130 hci_dev_lock(hdev);
3131
Johan Hedberg05cbf292013-03-15 17:07:07 -05003132 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3133 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3134 MGMT_STATUS_BUSY);
3135 goto unlock;
3136 }
3137
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003138 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3139 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3140 hdev);
3141 goto unlock;
3142 }
3143
Johan Hedberg33e38b32013-03-15 17:07:05 -05003144 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3145 data, len);
3146 if (!cmd) {
3147 err = -ENOMEM;
3148 goto unlock;
3149 }
3150
3151 hci_req_init(&req, hdev);
3152
Johan Hedberg406d7802013-03-15 17:07:09 -05003153 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003154
3155 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003156 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003157 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003158 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003159 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003160 }
3161
Johan Hedberg33e38b32013-03-15 17:07:05 -05003162unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003163 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003164
Antti Julkuf6422ec2011-06-22 13:11:56 +03003165 return err;
3166}
3167
Johan Hedberg3f706b72013-01-20 14:27:16 +02003168static bool ltk_is_valid(struct mgmt_ltk_info *key)
3169{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003170 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3171 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003172 if (key->master != 0x00 && key->master != 0x01)
3173 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003174 if (!bdaddr_type_is_le(key->addr.type))
3175 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003176 return true;
3177}
3178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003179static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003181{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003182 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3183 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003184 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003185
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003186 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003187
3188 expected_len = sizeof(*cp) + key_count *
3189 sizeof(struct mgmt_ltk_info);
3190 if (expected_len != len) {
3191 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003192 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003193 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003194 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003195 }
3196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003197 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003198
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003199 for (i = 0; i < key_count; i++) {
3200 struct mgmt_ltk_info *key = &cp->keys[i];
3201
Johan Hedberg3f706b72013-01-20 14:27:16 +02003202 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003203 return cmd_status(sk, hdev->id,
3204 MGMT_OP_LOAD_LONG_TERM_KEYS,
3205 MGMT_STATUS_INVALID_PARAMS);
3206 }
3207
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003208 hci_dev_lock(hdev);
3209
3210 hci_smp_ltks_clear(hdev);
3211
3212 for (i = 0; i < key_count; i++) {
3213 struct mgmt_ltk_info *key = &cp->keys[i];
3214 u8 type;
3215
3216 if (key->master)
3217 type = HCI_SMP_LTK;
3218 else
3219 type = HCI_SMP_LTK_SLAVE;
3220
Hemant Gupta4596fde2012-04-16 14:57:40 +05303221 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003222 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003223 type, 0, key->authenticated, key->val,
3224 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003225 }
3226
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003227 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3228 NULL, 0);
3229
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003230 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003231
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003232 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003233}
3234
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003235static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003236 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3237 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003238 bool var_len;
3239 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003240} mgmt_handlers[] = {
3241 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003242 { read_version, false, MGMT_READ_VERSION_SIZE },
3243 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3244 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3245 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3246 { set_powered, false, MGMT_SETTING_SIZE },
3247 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3248 { set_connectable, false, MGMT_SETTING_SIZE },
3249 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3250 { set_pairable, false, MGMT_SETTING_SIZE },
3251 { set_link_security, false, MGMT_SETTING_SIZE },
3252 { set_ssp, false, MGMT_SETTING_SIZE },
3253 { set_hs, false, MGMT_SETTING_SIZE },
3254 { set_le, false, MGMT_SETTING_SIZE },
3255 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3256 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3257 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3258 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3259 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3260 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3261 { disconnect, false, MGMT_DISCONNECT_SIZE },
3262 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3263 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3264 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3265 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3266 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3267 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3268 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3269 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3270 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3271 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3272 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3273 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3274 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3275 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3276 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3277 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3278 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3279 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3280 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003281 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003282};
3283
3284
Johan Hedberg03811012010-12-08 00:21:06 +02003285int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3286{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003287 void *buf;
3288 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003289 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003290 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003291 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003292 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003293 int err;
3294
3295 BT_DBG("got %zu bytes", msglen);
3296
3297 if (msglen < sizeof(*hdr))
3298 return -EINVAL;
3299
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003300 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003301 if (!buf)
3302 return -ENOMEM;
3303
3304 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3305 err = -EFAULT;
3306 goto done;
3307 }
3308
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003309 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003310 opcode = __le16_to_cpu(hdr->opcode);
3311 index = __le16_to_cpu(hdr->index);
3312 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003313
3314 if (len != msglen - sizeof(*hdr)) {
3315 err = -EINVAL;
3316 goto done;
3317 }
3318
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003319 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003320 hdev = hci_dev_get(index);
3321 if (!hdev) {
3322 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003323 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003324 goto done;
3325 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003326
3327 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3328 err = cmd_status(sk, index, opcode,
3329 MGMT_STATUS_INVALID_INDEX);
3330 goto done;
3331 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003332 }
3333
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003334 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003335 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003336 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003337 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003338 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003339 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003340 }
3341
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003342 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003343 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003344 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003345 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003346 goto done;
3347 }
3348
Johan Hedbergbe22b542012-03-01 22:24:41 +02003349 handler = &mgmt_handlers[opcode];
3350
3351 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003352 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003353 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003354 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003355 goto done;
3356 }
3357
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003358 if (hdev)
3359 mgmt_init_hdev(sk, hdev);
3360
3361 cp = buf + sizeof(*hdr);
3362
Johan Hedbergbe22b542012-03-01 22:24:41 +02003363 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003364 if (err < 0)
3365 goto done;
3366
Johan Hedberg03811012010-12-08 00:21:06 +02003367 err = msglen;
3368
3369done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003370 if (hdev)
3371 hci_dev_put(hdev);
3372
Johan Hedberg03811012010-12-08 00:21:06 +02003373 kfree(buf);
3374 return err;
3375}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003376
Johan Hedbergb24752f2011-11-03 14:40:33 +02003377static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3378{
3379 u8 *status = data;
3380
3381 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3382 mgmt_pending_remove(cmd);
3383}
3384
Johan Hedberg744cf192011-11-08 20:40:14 +02003385int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003386{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003387 if (!mgmt_valid_hdev(hdev))
3388 return -ENOTSUPP;
3389
Johan Hedberg744cf192011-11-08 20:40:14 +02003390 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003391}
3392
Johan Hedberg744cf192011-11-08 20:40:14 +02003393int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003394{
Johan Hedberg5f159032012-03-02 03:13:19 +02003395 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003396
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003397 if (!mgmt_valid_hdev(hdev))
3398 return -ENOTSUPP;
3399
Johan Hedberg744cf192011-11-08 20:40:14 +02003400 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003401
Johan Hedberg744cf192011-11-08 20:40:14 +02003402 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003403}
3404
Johan Hedberg73f22f62010-12-29 16:00:25 +02003405struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003406 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003407 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003408 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003409};
3410
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003411static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003412{
Johan Hedberg73f22f62010-12-29 16:00:25 +02003413 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003414
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003415 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003416
3417 list_del(&cmd->list);
3418
3419 if (match->sk == NULL) {
3420 match->sk = cmd->sk;
3421 sock_hold(match->sk);
3422 }
3423
3424 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003425}
Johan Hedberg5add6af2010-12-16 10:00:37 +02003426
Johan Hedberg890ea892013-03-15 17:06:52 -05003427static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003428{
Johan Hedberg890ea892013-03-15 17:06:52 -05003429 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003430 u8 scan = 0;
3431
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003432 /* Ensure that fast connectable is disabled. This function will
3433 * not do anything if the page scan parameters are already what
3434 * they should be.
3435 */
3436 write_fast_connectable(req, false);
3437
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003438 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3439 scan |= SCAN_PAGE;
3440 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3441 scan |= SCAN_INQUIRY;
3442
Johan Hedberg890ea892013-03-15 17:06:52 -05003443 if (scan)
3444 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003445}
3446
Johan Hedberg229ab392013-03-15 17:06:53 -05003447static void powered_complete(struct hci_dev *hdev, u8 status)
3448{
3449 struct cmd_lookup match = { NULL, hdev };
3450
3451 BT_DBG("status 0x%02x", status);
3452
3453 hci_dev_lock(hdev);
3454
3455 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3456
3457 new_settings(hdev, match.sk);
3458
3459 hci_dev_unlock(hdev);
3460
3461 if (match.sk)
3462 sock_put(match.sk);
3463}
3464
Johan Hedberg70da6242013-03-15 17:06:51 -05003465static int powered_update_hci(struct hci_dev *hdev)
3466{
Johan Hedberg890ea892013-03-15 17:06:52 -05003467 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003468 u8 link_sec;
3469
Johan Hedberg890ea892013-03-15 17:06:52 -05003470 hci_req_init(&req, hdev);
3471
Johan Hedberg70da6242013-03-15 17:06:51 -05003472 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3473 !lmp_host_ssp_capable(hdev)) {
3474 u8 ssp = 1;
3475
Johan Hedberg890ea892013-03-15 17:06:52 -05003476 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003477 }
3478
Johan Hedbergc73eee92013-04-19 18:35:21 +03003479 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3480 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003481 struct hci_cp_write_le_host_supported cp;
3482
3483 cp.le = 1;
3484 cp.simul = lmp_le_br_capable(hdev);
3485
3486 /* Check first if we already have the right
3487 * host state (host features set)
3488 */
3489 if (cp.le != lmp_host_le_capable(hdev) ||
3490 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003491 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3492 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003493 }
3494
3495 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3496 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003497 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3498 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003499
3500 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003501 set_bredr_scan(&req);
3502 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003503 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003504 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003505 }
3506
Johan Hedberg229ab392013-03-15 17:06:53 -05003507 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003508}
3509
Johan Hedberg744cf192011-11-08 20:40:14 +02003510int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003511{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003512 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003513 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3514 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003515 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003516
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003517 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3518 return 0;
3519
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003520 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003521 if (powered_update_hci(hdev) == 0)
3522 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003523
Johan Hedberg229ab392013-03-15 17:06:53 -05003524 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3525 &match);
3526 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003527 }
3528
Johan Hedberg229ab392013-03-15 17:06:53 -05003529 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3530 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3531
3532 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3533 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3534 zero_cod, sizeof(zero_cod), NULL);
3535
3536new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003537 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003538
3539 if (match.sk)
3540 sock_put(match.sk);
3541
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003542 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003543}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003544
Johan Hedberg96570ff2013-05-29 09:51:29 +03003545int mgmt_set_powered_failed(struct hci_dev *hdev, int err)
3546{
3547 struct pending_cmd *cmd;
3548 u8 status;
3549
3550 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3551 if (!cmd)
3552 return -ENOENT;
3553
3554 if (err == -ERFKILL)
3555 status = MGMT_STATUS_RFKILLED;
3556 else
3557 status = MGMT_STATUS_FAILED;
3558
3559 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
3560
3561 mgmt_pending_remove(cmd);
3562
3563 return err;
3564}
3565
Johan Hedberg744cf192011-11-08 20:40:14 +02003566int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003567{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003568 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003569 bool changed = false;
3570 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003571
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003572 if (discoverable) {
3573 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3574 changed = true;
3575 } else {
3576 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3577 changed = true;
3578 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003579
Johan Hedberged9b5f22012-02-21 20:47:06 +02003580 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003581 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003582
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003583 if (changed)
3584 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003585
Johan Hedberg73f22f62010-12-29 16:00:25 +02003586 if (match.sk)
3587 sock_put(match.sk);
3588
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003589 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003590}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003591
Johan Hedberg744cf192011-11-08 20:40:14 +02003592int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003593{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003594 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003595 bool changed = false;
3596 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003597
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003598 if (connectable) {
3599 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3600 changed = true;
3601 } else {
3602 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3603 changed = true;
3604 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003605
Johan Hedberg2b76f452013-03-15 17:07:04 -05003606 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003607
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003608 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003609 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003610
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003611 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003612}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003613
Johan Hedberg744cf192011-11-08 20:40:14 +02003614int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003615{
Johan Hedbergca69b792011-11-11 18:10:00 +02003616 u8 mgmt_err = mgmt_status(status);
3617
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003618 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003619 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003620 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003621
3622 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003623 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003624 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003625
3626 return 0;
3627}
3628
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003629int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3630 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003631{
Johan Hedberg86742e12011-11-07 23:13:38 +02003632 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003633
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003634 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003635
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003636 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003637 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003638 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003639 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003640 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003641 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003642
Johan Hedberg744cf192011-11-08 20:40:14 +02003643 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003644}
Johan Hedbergf7520542011-01-20 12:34:39 +02003645
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003646int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3647{
3648 struct mgmt_ev_new_long_term_key ev;
3649
3650 memset(&ev, 0, sizeof(ev));
3651
3652 ev.store_hint = persistent;
3653 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003654 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003655 ev.key.authenticated = key->authenticated;
3656 ev.key.enc_size = key->enc_size;
3657 ev.key.ediv = key->ediv;
3658
3659 if (key->type == HCI_SMP_LTK)
3660 ev.key.master = 1;
3661
3662 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3663 memcpy(ev.key.val, key->val, sizeof(key->val));
3664
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003665 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3666 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003667}
3668
Johan Hedbergafc747a2012-01-15 18:11:07 +02003669int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003670 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3671 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003672{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003673 char buf[512];
3674 struct mgmt_ev_device_connected *ev = (void *) buf;
3675 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003676
Johan Hedbergb644ba32012-01-17 21:48:47 +02003677 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003678 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003679
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003680 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003681
Johan Hedbergb644ba32012-01-17 21:48:47 +02003682 if (name_len > 0)
3683 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003684 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003685
3686 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003687 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003688 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003689
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003690 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003691
3692 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003693 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003694}
3695
Johan Hedberg8962ee72011-01-20 12:40:27 +02003696static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3697{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003698 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003699 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003700 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003701
Johan Hedberg88c3df12012-02-09 14:27:38 +02003702 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3703 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003704
Johan Hedbergaee9b212012-02-18 15:07:59 +02003705 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003706 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003707
3708 *sk = cmd->sk;
3709 sock_hold(*sk);
3710
Johan Hedberga664b5b2011-02-19 12:06:02 -03003711 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003712}
3713
Johan Hedberg124f6e32012-02-09 13:50:12 +02003714static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003715{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003716 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003717 struct mgmt_cp_unpair_device *cp = cmd->param;
3718 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003719
3720 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003721 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3722 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003723
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003724 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3725
Johan Hedbergaee9b212012-02-18 15:07:59 +02003726 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003727
3728 mgmt_pending_remove(cmd);
3729}
3730
Johan Hedbergafc747a2012-01-15 18:11:07 +02003731int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003732 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003733{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003734 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003735 struct sock *sk = NULL;
3736 int err;
3737
Johan Hedberg744cf192011-11-08 20:40:14 +02003738 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003739
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003740 bacpy(&ev.addr.bdaddr, bdaddr);
3741 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3742 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003743
Johan Hedbergafc747a2012-01-15 18:11:07 +02003744 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003745 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003746
3747 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003748 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003749
Johan Hedberg124f6e32012-02-09 13:50:12 +02003750 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003751 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003752
Johan Hedberg8962ee72011-01-20 12:40:27 +02003753 return err;
3754}
3755
Johan Hedberg88c3df12012-02-09 14:27:38 +02003756int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003757 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003758{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003759 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003760 struct pending_cmd *cmd;
3761 int err;
3762
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003763 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3764 hdev);
3765
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003766 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003767 if (!cmd)
3768 return -ENOENT;
3769
Johan Hedberg88c3df12012-02-09 14:27:38 +02003770 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003771 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003772
Johan Hedberg88c3df12012-02-09 14:27:38 +02003773 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003774 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003775
Johan Hedberga664b5b2011-02-19 12:06:02 -03003776 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003777
3778 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003779}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003780
Johan Hedberg48264f02011-11-09 13:58:58 +02003781int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003782 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003783{
3784 struct mgmt_ev_connect_failed ev;
3785
Johan Hedberg4c659c32011-11-07 23:13:39 +02003786 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003787 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003788 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003789
Johan Hedberg744cf192011-11-08 20:40:14 +02003790 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003791}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003792
Johan Hedberg744cf192011-11-08 20:40:14 +02003793int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003794{
3795 struct mgmt_ev_pin_code_request ev;
3796
Johan Hedbergd8457692012-02-17 14:24:57 +02003797 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003798 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003799 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003800
Johan Hedberg744cf192011-11-08 20:40:14 +02003801 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003802 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003803}
3804
Johan Hedberg744cf192011-11-08 20:40:14 +02003805int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003806 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003807{
3808 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003809 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003810 int err;
3811
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003812 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003813 if (!cmd)
3814 return -ENOENT;
3815
Johan Hedbergd8457692012-02-17 14:24:57 +02003816 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003817 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003818
Johan Hedbergaee9b212012-02-18 15:07:59 +02003819 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003820 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003821
Johan Hedberga664b5b2011-02-19 12:06:02 -03003822 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003823
3824 return err;
3825}
3826
Johan Hedberg744cf192011-11-08 20:40:14 +02003827int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003828 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003829{
3830 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003831 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003832 int err;
3833
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003834 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003835 if (!cmd)
3836 return -ENOENT;
3837
Johan Hedbergd8457692012-02-17 14:24:57 +02003838 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003839 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003840
Johan Hedbergaee9b212012-02-18 15:07:59 +02003841 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003842 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003843
Johan Hedberga664b5b2011-02-19 12:06:02 -03003844 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003845
3846 return err;
3847}
Johan Hedberga5c29682011-02-19 12:05:57 -03003848
Johan Hedberg744cf192011-11-08 20:40:14 +02003849int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003850 u8 link_type, u8 addr_type, __le32 value,
3851 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003852{
3853 struct mgmt_ev_user_confirm_request ev;
3854
Johan Hedberg744cf192011-11-08 20:40:14 +02003855 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003856
Johan Hedberg272d90d2012-02-09 15:26:12 +02003857 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003858 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003859 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003860 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003861
Johan Hedberg744cf192011-11-08 20:40:14 +02003862 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003863 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003864}
3865
Johan Hedberg272d90d2012-02-09 15:26:12 +02003866int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003867 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003868{
3869 struct mgmt_ev_user_passkey_request ev;
3870
3871 BT_DBG("%s", hdev->name);
3872
Johan Hedberg272d90d2012-02-09 15:26:12 +02003873 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003874 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003875
3876 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003877 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003878}
3879
Brian Gix0df4c182011-11-16 13:53:13 -08003880static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003881 u8 link_type, u8 addr_type, u8 status,
3882 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003883{
3884 struct pending_cmd *cmd;
3885 struct mgmt_rp_user_confirm_reply rp;
3886 int err;
3887
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003888 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003889 if (!cmd)
3890 return -ENOENT;
3891
Johan Hedberg272d90d2012-02-09 15:26:12 +02003892 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003893 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003894 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003895 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003896
Johan Hedberga664b5b2011-02-19 12:06:02 -03003897 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003898
3899 return err;
3900}
3901
Johan Hedberg744cf192011-11-08 20:40:14 +02003902int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003903 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003904{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003905 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003906 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003907}
3908
Johan Hedberg272d90d2012-02-09 15:26:12 +02003909int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003910 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003911{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003912 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003913 status,
3914 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003915}
Johan Hedberg2a611692011-02-19 12:06:00 -03003916
Brian Gix604086b2011-11-23 08:28:33 -08003917int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003918 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003919{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003920 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003921 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003922}
3923
Johan Hedberg272d90d2012-02-09 15:26:12 +02003924int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003925 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003926{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003927 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003928 status,
3929 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003930}
3931
Johan Hedberg92a25252012-09-06 18:39:26 +03003932int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3933 u8 link_type, u8 addr_type, u32 passkey,
3934 u8 entered)
3935{
3936 struct mgmt_ev_passkey_notify ev;
3937
3938 BT_DBG("%s", hdev->name);
3939
3940 bacpy(&ev.addr.bdaddr, bdaddr);
3941 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3942 ev.passkey = __cpu_to_le32(passkey);
3943 ev.entered = entered;
3944
3945 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3946}
3947
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003948int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003949 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003950{
3951 struct mgmt_ev_auth_failed ev;
3952
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003953 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003954 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003955 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003956
Johan Hedberg744cf192011-11-08 20:40:14 +02003957 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003958}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003959
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003960int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3961{
3962 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003963 bool changed = false;
3964 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003965
3966 if (status) {
3967 u8 mgmt_err = mgmt_status(status);
3968 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003969 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003970 return 0;
3971 }
3972
Johan Hedberg47990ea2012-02-22 11:58:37 +02003973 if (test_bit(HCI_AUTH, &hdev->flags)) {
3974 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3975 changed = true;
3976 } else {
3977 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3978 changed = true;
3979 }
3980
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003981 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003982 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003983
Johan Hedberg47990ea2012-02-22 11:58:37 +02003984 if (changed)
3985 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003986
3987 if (match.sk)
3988 sock_put(match.sk);
3989
3990 return err;
3991}
3992
Johan Hedberg890ea892013-03-15 17:06:52 -05003993static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02003994{
Johan Hedberg890ea892013-03-15 17:06:52 -05003995 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02003996 struct hci_cp_write_eir cp;
3997
Johan Hedberg976eb202012-10-24 21:12:01 +03003998 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003999 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004000
Johan Hedbergc80da272012-02-22 15:38:48 +02004001 memset(hdev->eir, 0, sizeof(hdev->eir));
4002
Johan Hedbergcacaf522012-02-21 00:52:42 +02004003 memset(&cp, 0, sizeof(cp));
4004
Johan Hedberg890ea892013-03-15 17:06:52 -05004005 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004006}
4007
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004008int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004009{
4010 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004011 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004012 bool changed = false;
4013 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004014
4015 if (status) {
4016 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004017
4018 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004019 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004020 err = new_settings(hdev, NULL);
4021
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004022 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4023 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004024
4025 return err;
4026 }
4027
4028 if (enable) {
4029 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4030 changed = true;
4031 } else {
4032 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
4033 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004034 }
4035
4036 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4037
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004038 if (changed)
4039 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004040
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004041 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004042 sock_put(match.sk);
4043
Johan Hedberg890ea892013-03-15 17:06:52 -05004044 hci_req_init(&req, hdev);
4045
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004046 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004047 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004048 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004049 clear_eir(&req);
4050
4051 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004052
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004053 return err;
4054}
4055
Johan Hedberg92da6092013-03-15 17:06:55 -05004056static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004057{
4058 struct cmd_lookup *match = data;
4059
Johan Hedberg90e70452012-02-23 23:09:40 +02004060 if (match->sk == NULL) {
4061 match->sk = cmd->sk;
4062 sock_hold(match->sk);
4063 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004064}
4065
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004066int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004067 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004068{
Johan Hedberg90e70452012-02-23 23:09:40 +02004069 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4070 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004071
Johan Hedberg92da6092013-03-15 17:06:55 -05004072 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4073 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4074 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004075
4076 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004077 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4078 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004079
4080 if (match.sk)
4081 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004082
4083 return err;
4084}
4085
Johan Hedberg744cf192011-11-08 20:40:14 +02004086int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004087{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004088 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004089 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004090
Johan Hedberg13928972013-03-15 17:07:00 -05004091 if (status)
4092 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004093
4094 memset(&ev, 0, sizeof(ev));
4095 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004096 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004097
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004098 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004099 if (!cmd) {
4100 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004101
Johan Hedberg13928972013-03-15 17:07:00 -05004102 /* If this is a HCI command related to powering on the
4103 * HCI dev don't send any mgmt signals.
4104 */
4105 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4106 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004107 }
4108
Johan Hedberg13928972013-03-15 17:07:00 -05004109 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4110 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004111}
Szymon Jancc35938b2011-03-22 13:12:21 +01004112
Johan Hedberg744cf192011-11-08 20:40:14 +02004113int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004114 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004115{
4116 struct pending_cmd *cmd;
4117 int err;
4118
Johan Hedberg744cf192011-11-08 20:40:14 +02004119 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004120
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004121 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004122 if (!cmd)
4123 return -ENOENT;
4124
4125 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004126 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4127 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004128 } else {
4129 struct mgmt_rp_read_local_oob_data rp;
4130
4131 memcpy(rp.hash, hash, sizeof(rp.hash));
4132 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4133
Johan Hedberg744cf192011-11-08 20:40:14 +02004134 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004135 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4136 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004137 }
4138
4139 mgmt_pending_remove(cmd);
4140
4141 return err;
4142}
Johan Hedberge17acd42011-03-30 23:57:16 +03004143
Johan Hedberg06199cf2012-02-22 16:37:11 +02004144int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
4145{
4146 struct cmd_lookup match = { NULL, hdev };
4147 bool changed = false;
4148 int err = 0;
4149
4150 if (status) {
4151 u8 mgmt_err = mgmt_status(status);
4152
4153 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004154 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01004155 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02004156
Szymon Jancd97dcb62012-03-16 16:02:56 +01004157 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
4158 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02004159
4160 return err;
4161 }
4162
4163 if (enable) {
4164 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4165 changed = true;
4166 } else {
4167 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4168 changed = true;
4169 }
4170
4171 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
4172
4173 if (changed)
4174 err = new_settings(hdev, match.sk);
4175
4176 if (match.sk)
4177 sock_put(match.sk);
4178
4179 return err;
4180}
4181
Johan Hedberg48264f02011-11-09 13:58:58 +02004182int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004183 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4184 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004185{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004186 char buf[512];
4187 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004188 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004189
Andre Guedes12602d02013-04-30 15:29:40 -03004190 if (!hci_discovery_active(hdev))
4191 return -EPERM;
4192
Johan Hedberg1dc06092012-01-15 21:01:23 +02004193 /* Leave 5 bytes for a potential CoD field */
4194 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004195 return -EINVAL;
4196
Johan Hedberg1dc06092012-01-15 21:01:23 +02004197 memset(buf, 0, sizeof(buf));
4198
Johan Hedberge319d2e2012-01-15 19:51:59 +02004199 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004200 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004201 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004202 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304203 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004204 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304205 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004206
Johan Hedberg1dc06092012-01-15 21:01:23 +02004207 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004208 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004209
Johan Hedberg1dc06092012-01-15 21:01:23 +02004210 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4211 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004212 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004213
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004214 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004215 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004216
Johan Hedberge319d2e2012-01-15 19:51:59 +02004217 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004218}
Johan Hedberga88a9652011-03-30 13:18:12 +03004219
Johan Hedbergb644ba32012-01-17 21:48:47 +02004220int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004221 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004222{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004223 struct mgmt_ev_device_found *ev;
4224 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4225 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004226
Johan Hedbergb644ba32012-01-17 21:48:47 +02004227 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004228
Johan Hedbergb644ba32012-01-17 21:48:47 +02004229 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004230
Johan Hedbergb644ba32012-01-17 21:48:47 +02004231 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004232 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004233 ev->rssi = rssi;
4234
4235 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004236 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004237
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004238 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004239
Johan Hedberg053c7e02012-02-04 00:06:00 +02004240 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004241 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004242}
Johan Hedberg314b2382011-04-27 10:29:57 -04004243
Johan Hedberg744cf192011-11-08 20:40:14 +02004244int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004245{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004246 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004247 struct pending_cmd *cmd;
4248
Andre Guedes343fb142011-11-22 17:14:19 -03004249 BT_DBG("%s discovering %u", hdev->name, discovering);
4250
Johan Hedberg164a6e72011-11-01 17:06:44 +02004251 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004252 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004253 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004254 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004255
4256 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004257 u8 type = hdev->discovery.type;
4258
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004259 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4260 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004261 mgmt_pending_remove(cmd);
4262 }
4263
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004264 memset(&ev, 0, sizeof(ev));
4265 ev.type = hdev->discovery.type;
4266 ev.discovering = discovering;
4267
4268 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004269}
Antti Julku5e762442011-08-25 16:48:02 +03004270
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004271int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004272{
4273 struct pending_cmd *cmd;
4274 struct mgmt_ev_device_blocked ev;
4275
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004276 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004277
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004278 bacpy(&ev.addr.bdaddr, bdaddr);
4279 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004280
Johan Hedberg744cf192011-11-08 20:40:14 +02004281 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004282 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004283}
4284
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004285int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004286{
4287 struct pending_cmd *cmd;
4288 struct mgmt_ev_device_unblocked ev;
4289
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004290 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004291
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004292 bacpy(&ev.addr.bdaddr, bdaddr);
4293 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004294
Johan Hedberg744cf192011-11-08 20:40:14 +02004295 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004296 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004297}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01004298
4299module_param(enable_hs, bool, 0644);
4300MODULE_PARM_DESC(enable_hs, "Enable High Speed support");