blob: 61d4b190eebf441f48bcac85c43ba07dbfca5755 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060038#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800105#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200106
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200107#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
108 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
109
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200110struct pending_cmd {
111 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200112 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100114 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200115 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300116 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117};
118
Johan Hedbergca69b792011-11-11 18:10:00 +0200119/* HCI to MGMT error code conversion table */
120static u8 mgmt_status_table[] = {
121 MGMT_STATUS_SUCCESS,
122 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
123 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
124 MGMT_STATUS_FAILED, /* Hardware Failure */
125 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
126 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
127 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
128 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
129 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
130 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
131 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
132 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
133 MGMT_STATUS_BUSY, /* Command Disallowed */
134 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
135 MGMT_STATUS_REJECTED, /* Rejected Security */
136 MGMT_STATUS_REJECTED, /* Rejected Personal */
137 MGMT_STATUS_TIMEOUT, /* Host Timeout */
138 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
139 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
140 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
141 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
142 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
143 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
144 MGMT_STATUS_BUSY, /* Repeated Attempts */
145 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
146 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
147 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
148 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
149 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
150 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
151 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
152 MGMT_STATUS_FAILED, /* Unspecified Error */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
154 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
155 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
156 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
157 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
158 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
159 MGMT_STATUS_FAILED, /* Unit Link Key Used */
160 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
161 MGMT_STATUS_TIMEOUT, /* Instant Passed */
162 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
163 MGMT_STATUS_FAILED, /* Transaction Collision */
164 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
165 MGMT_STATUS_REJECTED, /* QoS Rejected */
166 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
167 MGMT_STATUS_REJECTED, /* Insufficient Security */
168 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
169 MGMT_STATUS_BUSY, /* Role Switch Pending */
170 MGMT_STATUS_FAILED, /* Slot Violation */
171 MGMT_STATUS_FAILED, /* Role Switch Failed */
172 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
173 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
174 MGMT_STATUS_BUSY, /* Host Busy Pairing */
175 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
176 MGMT_STATUS_BUSY, /* Controller Busy */
177 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
178 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
179 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
180 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
181 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
182};
183
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300184bool mgmt_valid_hdev(struct hci_dev *hdev)
185{
186 return hdev->dev_type == HCI_BREDR;
187}
188
Johan Hedbergca69b792011-11-11 18:10:00 +0200189static u8 mgmt_status(u8 hci_status)
190{
191 if (hci_status < ARRAY_SIZE(mgmt_status_table))
192 return mgmt_status_table[hci_status];
193
194 return MGMT_STATUS_FAILED;
195}
196
Szymon Janc4e51eae2011-02-25 19:05:48 +0100197static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200198{
199 struct sk_buff *skb;
200 struct mgmt_hdr *hdr;
201 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300202 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Szymon Janc34eb5252011-02-28 14:10:08 +0100204 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205
Andre Guedes790eff42012-06-07 19:05:46 -0300206 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207 if (!skb)
208 return -ENOMEM;
209
210 hdr = (void *) skb_put(skb, sizeof(*hdr));
211
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530212 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100213 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214 hdr->len = cpu_to_le16(sizeof(*ev));
215
216 ev = (void *) skb_put(skb, sizeof(*ev));
217 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200218 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200219
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300220 err = sock_queue_rcv_skb(sk, skb);
221 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200222 kfree_skb(skb);
223
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300224 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200225}
226
Johan Hedbergaee9b212012-02-18 15:07:59 +0200227static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300228 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200229{
230 struct sk_buff *skb;
231 struct mgmt_hdr *hdr;
232 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200234
235 BT_DBG("sock %p", sk);
236
Andre Guedes790eff42012-06-07 19:05:46 -0300237 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200238 if (!skb)
239 return -ENOMEM;
240
241 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200242
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530243 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100244 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200248 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200249 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100250
251 if (rp)
252 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200253
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300254 err = sock_queue_rcv_skb(sk, skb);
255 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200256 kfree_skb(skb);
257
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100258 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200259}
260
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300261static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
262 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200263{
264 struct mgmt_rp_read_version rp;
265
266 BT_DBG("sock %p", sk);
267
268 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200269 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200270
Johan Hedbergaee9b212012-02-18 15:07:59 +0200271 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300272 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200273}
274
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300275static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
276 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200277{
278 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200279 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
280 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200281 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200282 size_t rp_size;
283 int i, err;
284
285 BT_DBG("sock %p", sk);
286
287 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
288
289 rp = kmalloc(rp_size, GFP_KERNEL);
290 if (!rp)
291 return -ENOMEM;
292
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200293 rp->num_commands = __constant_cpu_to_le16(num_commands);
294 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295
296 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
297 put_unaligned_le16(mgmt_commands[i], opcode);
298
299 for (i = 0; i < num_events; i++, opcode++)
300 put_unaligned_le16(mgmt_events[i], opcode);
301
Johan Hedbergaee9b212012-02-18 15:07:59 +0200302 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300303 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304 kfree(rp);
305
306 return err;
307}
308
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300309static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
310 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200313 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200314 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300316 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200317
318 BT_DBG("sock %p", sk);
319
320 read_lock(&hci_dev_list_lock);
321
322 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300323 list_for_each_entry(d, &hci_dev_list, list) {
324 if (!mgmt_valid_hdev(d))
325 continue;
326
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 count++;
328 }
329
Johan Hedberga38528f2011-01-22 06:46:43 +0200330 rp_len = sizeof(*rp) + (2 * count);
331 rp = kmalloc(rp_len, GFP_ATOMIC);
332 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100333 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200334 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100335 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200336
Johan Hedberg476e44c2012-10-19 20:10:46 +0300337 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200339 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200340 continue;
341
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700342 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
343 continue;
344
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300345 if (!mgmt_valid_hdev(d))
346 continue;
347
Johan Hedberg476e44c2012-10-19 20:10:46 +0300348 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 BT_DBG("Added hci%u", d->id);
350 }
351
Johan Hedberg476e44c2012-10-19 20:10:46 +0300352 rp->num_controllers = cpu_to_le16(count);
353 rp_len = sizeof(*rp) + (2 * count);
354
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b212012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Andre Guedes9a1a1992012-07-24 15:03:48 -0300372 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Andre Guedesed3fa312012-07-24 15:03:46 -0300375 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300376 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500377 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
378 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300379 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380 settings |= MGMT_SETTING_BREDR;
381 settings |= MGMT_SETTING_LINK_SECURITY;
382 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200383
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384 if (enable_hs)
385 settings |= MGMT_SETTING_HS;
386
Andre Guedesc383ddc2012-07-24 15:03:47 -0300387 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200388 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200389
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200390 return settings;
391}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200392
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200393static u32 get_current_settings(struct hci_dev *hdev)
394{
395 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200396
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200397 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 settings |= MGMT_SETTING_POWERED;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_CONNECTABLE;
402
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500403 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
404 settings |= MGMT_SETTING_FAST_CONNECTABLE;
405
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200406 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_DISCOVERABLE;
408
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200409 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_PAIRABLE;
411
Andre Guedesed3fa312012-07-24 15:03:46 -0300412 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_BREDR;
414
Johan Hedberg06199cf2012-02-22 16:37:11 +0200415 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200417
Johan Hedberg47990ea2012-02-22 11:58:37 +0200418 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200420
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200421 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200423
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200424 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
425 settings |= MGMT_SETTING_HS;
426
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200427 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200428}
429
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300430#define PNP_INFO_SVCLASS_ID 0x1200
431
Johan Hedberg213202e2013-01-27 00:31:33 +0200432static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
433{
434 u8 *ptr = data, *uuids_start = NULL;
435 struct bt_uuid *uuid;
436
437 if (len < 4)
438 return ptr;
439
440 list_for_each_entry(uuid, &hdev->uuids, list) {
441 u16 uuid16;
442
443 if (uuid->size != 16)
444 continue;
445
446 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
447 if (uuid16 < 0x1100)
448 continue;
449
450 if (uuid16 == PNP_INFO_SVCLASS_ID)
451 continue;
452
453 if (!uuids_start) {
454 uuids_start = ptr;
455 uuids_start[0] = 1;
456 uuids_start[1] = EIR_UUID16_ALL;
457 ptr += 2;
458 }
459
460 /* Stop if not enough space to put next UUID */
461 if ((ptr - data) + sizeof(u16) > len) {
462 uuids_start[1] = EIR_UUID16_SOME;
463 break;
464 }
465
466 *ptr++ = (uuid16 & 0x00ff);
467 *ptr++ = (uuid16 & 0xff00) >> 8;
468 uuids_start[0] += sizeof(uuid16);
469 }
470
471 return ptr;
472}
473
Johan Hedbergcdf19632013-01-27 00:31:34 +0200474static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
475{
476 u8 *ptr = data, *uuids_start = NULL;
477 struct bt_uuid *uuid;
478
479 if (len < 6)
480 return ptr;
481
482 list_for_each_entry(uuid, &hdev->uuids, list) {
483 if (uuid->size != 32)
484 continue;
485
486 if (!uuids_start) {
487 uuids_start = ptr;
488 uuids_start[0] = 1;
489 uuids_start[1] = EIR_UUID32_ALL;
490 ptr += 2;
491 }
492
493 /* Stop if not enough space to put next UUID */
494 if ((ptr - data) + sizeof(u32) > len) {
495 uuids_start[1] = EIR_UUID32_SOME;
496 break;
497 }
498
499 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
500 ptr += sizeof(u32);
501 uuids_start[0] += sizeof(u32);
502 }
503
504 return ptr;
505}
506
Johan Hedbergc00d5752013-01-27 00:31:35 +0200507static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
508{
509 u8 *ptr = data, *uuids_start = NULL;
510 struct bt_uuid *uuid;
511
512 if (len < 18)
513 return ptr;
514
515 list_for_each_entry(uuid, &hdev->uuids, list) {
516 if (uuid->size != 128)
517 continue;
518
519 if (!uuids_start) {
520 uuids_start = ptr;
521 uuids_start[0] = 1;
522 uuids_start[1] = EIR_UUID128_ALL;
523 ptr += 2;
524 }
525
526 /* Stop if not enough space to put next UUID */
527 if ((ptr - data) + 16 > len) {
528 uuids_start[1] = EIR_UUID128_SOME;
529 break;
530 }
531
532 memcpy(ptr, uuid->uuid, 16);
533 ptr += 16;
534 uuids_start[0] += 16;
535 }
536
537 return ptr;
538}
539
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300540static void create_eir(struct hci_dev *hdev, u8 *data)
541{
542 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300543 size_t name_len;
544
545 name_len = strlen(hdev->dev_name);
546
547 if (name_len > 0) {
548 /* EIR Data type */
549 if (name_len > 48) {
550 name_len = 48;
551 ptr[1] = EIR_NAME_SHORT;
552 } else
553 ptr[1] = EIR_NAME_COMPLETE;
554
555 /* EIR Data length */
556 ptr[0] = name_len + 1;
557
558 memcpy(ptr + 2, hdev->dev_name, name_len);
559
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300560 ptr += (name_len + 2);
561 }
562
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100563 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700564 ptr[0] = 2;
565 ptr[1] = EIR_TX_POWER;
566 ptr[2] = (u8) hdev->inq_tx_power;
567
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700568 ptr += 3;
569 }
570
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700571 if (hdev->devid_source > 0) {
572 ptr[0] = 9;
573 ptr[1] = EIR_DEVICE_ID;
574
575 put_unaligned_le16(hdev->devid_source, ptr + 2);
576 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
577 put_unaligned_le16(hdev->devid_product, ptr + 6);
578 put_unaligned_le16(hdev->devid_version, ptr + 8);
579
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700580 ptr += 10;
581 }
582
Johan Hedberg213202e2013-01-27 00:31:33 +0200583 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200584 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200585 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300586}
587
Johan Hedberg890ea892013-03-15 17:06:52 -0500588static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300589{
Johan Hedberg890ea892013-03-15 17:06:52 -0500590 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300591 struct hci_cp_write_eir cp;
592
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200593 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200595
Johan Hedberg976eb202012-10-24 21:12:01 +0300596 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500597 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300598
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200599 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200602 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500603 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300604
605 memset(&cp, 0, sizeof(cp));
606
607 create_eir(hdev, cp.data);
608
609 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500610 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300611
612 memcpy(hdev->eir, cp.data, sizeof(cp.data));
613
Johan Hedberg890ea892013-03-15 17:06:52 -0500614 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300615}
616
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200617static u8 get_service_classes(struct hci_dev *hdev)
618{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300619 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620 u8 val = 0;
621
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300622 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200623 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624
625 return val;
626}
627
Johan Hedberg890ea892013-03-15 17:06:52 -0500628static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200629{
Johan Hedberg890ea892013-03-15 17:06:52 -0500630 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200631 u8 cod[3];
632
633 BT_DBG("%s", hdev->name);
634
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200635 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500636 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200637
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200638 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500639 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200640
641 cod[0] = hdev->minor_class;
642 cod[1] = hdev->major_class;
643 cod[2] = get_service_classes(hdev);
644
645 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500646 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200647
Johan Hedberg890ea892013-03-15 17:06:52 -0500648 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200649}
650
Johan Hedberg7d785252011-12-15 00:47:39 +0200651static void service_cache_off(struct work_struct *work)
652{
653 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300654 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500655 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200656
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200657 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200658 return;
659
Johan Hedberg890ea892013-03-15 17:06:52 -0500660 hci_req_init(&req, hdev);
661
Johan Hedberg7d785252011-12-15 00:47:39 +0200662 hci_dev_lock(hdev);
663
Johan Hedberg890ea892013-03-15 17:06:52 -0500664 update_eir(&req);
665 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200666
667 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500668
669 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200670}
671
Johan Hedberg6a919082012-02-28 06:17:26 +0200672static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200673{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200674 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200675 return;
676
Johan Hedberg4f87da82012-03-02 19:55:56 +0200677 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200678
Johan Hedberg4f87da82012-03-02 19:55:56 +0200679 /* Non-mgmt controlled devices get this bit set
680 * implicitly so that pairing works for them, however
681 * for mgmt we require user-space to explicitly enable
682 * it
683 */
684 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200685}
686
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200687static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300688 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200689{
690 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200691
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200692 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200693
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300694 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedberg03811012010-12-08 00:21:06 +0200696 memset(&rp, 0, sizeof(rp));
697
Johan Hedberg03811012010-12-08 00:21:06 +0200698 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200699
700 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200701 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200702
703 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
704 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
705
706 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200707
708 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200709 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200710
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300711 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200712
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200713 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300714 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200715}
716
717static void mgmt_pending_free(struct pending_cmd *cmd)
718{
719 sock_put(cmd->sk);
720 kfree(cmd->param);
721 kfree(cmd);
722}
723
724static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300725 struct hci_dev *hdev, void *data,
726 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200727{
728 struct pending_cmd *cmd;
729
Andre Guedes12b94562012-06-07 19:05:45 -0300730 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200731 if (!cmd)
732 return NULL;
733
734 cmd->opcode = opcode;
735 cmd->index = hdev->id;
736
Andre Guedes12b94562012-06-07 19:05:45 -0300737 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200738 if (!cmd->param) {
739 kfree(cmd);
740 return NULL;
741 }
742
743 if (data)
744 memcpy(cmd->param, data, len);
745
746 cmd->sk = sk;
747 sock_hold(sk);
748
749 list_add(&cmd->list, &hdev->mgmt_pending);
750
751 return cmd;
752}
753
754static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300755 void (*cb)(struct pending_cmd *cmd,
756 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300757 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200758{
Andre Guedesa3d09352013-02-01 11:21:30 -0300759 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200760
Andre Guedesa3d09352013-02-01 11:21:30 -0300761 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200762 if (opcode > 0 && cmd->opcode != opcode)
763 continue;
764
765 cb(cmd, data);
766 }
767}
768
769static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
770{
771 struct pending_cmd *cmd;
772
773 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
774 if (cmd->opcode == opcode)
775 return cmd;
776 }
777
778 return NULL;
779}
780
781static void mgmt_pending_remove(struct pending_cmd *cmd)
782{
783 list_del(&cmd->list);
784 mgmt_pending_free(cmd);
785}
786
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200788{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200789 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200790
Johan Hedbergaee9b212012-02-18 15:07:59 +0200791 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300792 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200793}
794
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200795static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300796 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300798 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200799 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200800 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200801
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200802 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200803
Johan Hedberga7e80f22013-01-09 16:05:19 +0200804 if (cp->val != 0x00 && cp->val != 0x01)
805 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
806 MGMT_STATUS_INVALID_PARAMS);
807
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300808 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200809
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300810 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
811 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
812 MGMT_STATUS_BUSY);
813 goto failed;
814 }
815
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100816 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
817 cancel_delayed_work(&hdev->power_off);
818
819 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200820 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
821 data, len);
822 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100823 goto failed;
824 }
825 }
826
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200827 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200828 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200829 goto failed;
830 }
831
Johan Hedberg03811012010-12-08 00:21:06 +0200832 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
833 if (!cmd) {
834 err = -ENOMEM;
835 goto failed;
836 }
837
838 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200839 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200840 else
Johan Hedberg19202572013-01-14 22:33:51 +0200841 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200842
843 err = 0;
844
845failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300846 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200847 return err;
848}
849
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300850static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
851 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200852{
853 struct sk_buff *skb;
854 struct mgmt_hdr *hdr;
855
Andre Guedes790eff42012-06-07 19:05:46 -0300856 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200857 if (!skb)
858 return -ENOMEM;
859
860 hdr = (void *) skb_put(skb, sizeof(*hdr));
861 hdr->opcode = cpu_to_le16(event);
862 if (hdev)
863 hdr->index = cpu_to_le16(hdev->id);
864 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530865 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200866 hdr->len = cpu_to_le16(data_len);
867
868 if (data)
869 memcpy(skb_put(skb, data_len), data, data_len);
870
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100871 /* Time stamp */
872 __net_timestamp(skb);
873
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200874 hci_send_to_control(skb, skip_sk);
875 kfree_skb(skb);
876
877 return 0;
878}
879
880static int new_settings(struct hci_dev *hdev, struct sock *skip)
881{
882 __le32 ev;
883
884 ev = cpu_to_le32(get_current_settings(hdev));
885
886 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
887}
888
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300889struct cmd_lookup {
890 struct sock *sk;
891 struct hci_dev *hdev;
892 u8 mgmt_status;
893};
894
895static void settings_rsp(struct pending_cmd *cmd, void *data)
896{
897 struct cmd_lookup *match = data;
898
899 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
900
901 list_del(&cmd->list);
902
903 if (match->sk == NULL) {
904 match->sk = cmd->sk;
905 sock_hold(match->sk);
906 }
907
908 mgmt_pending_free(cmd);
909}
910
911static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
912{
913 u8 *status = data;
914
915 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
916 mgmt_pending_remove(cmd);
917}
918
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200919static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300920 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200921{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300922 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200923 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200924 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200925 u8 scan;
926 int err;
927
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200928 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200929
Johan Hedberg33c525c2012-10-24 21:11:58 +0300930 if (!lmp_bredr_capable(hdev))
931 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
932 MGMT_STATUS_NOT_SUPPORTED);
933
Johan Hedberga7e80f22013-01-09 16:05:19 +0200934 if (cp->val != 0x00 && cp->val != 0x01)
935 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
936 MGMT_STATUS_INVALID_PARAMS);
937
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700938 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100939 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200940 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300941 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200942
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300943 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200944
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200945 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200946 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300947 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200948 goto failed;
949 }
950
951 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300952 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200953 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300954 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200955 goto failed;
956 }
957
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200958 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200959 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300960 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200961 goto failed;
962 }
963
964 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200965 bool changed = false;
966
967 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
968 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
969 changed = true;
970 }
971
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200972 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200973 if (err < 0)
974 goto failed;
975
976 if (changed)
977 err = new_settings(hdev, sk);
978
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 goto failed;
980 }
981
982 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100983 if (hdev->discov_timeout > 0) {
984 cancel_delayed_work(&hdev->discov_off);
985 hdev->discov_timeout = 0;
986 }
987
988 if (cp->val && timeout > 0) {
989 hdev->discov_timeout = timeout;
990 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
991 msecs_to_jiffies(hdev->discov_timeout * 1000));
992 }
993
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200994 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200995 goto failed;
996 }
997
998 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
999 if (!cmd) {
1000 err = -ENOMEM;
1001 goto failed;
1002 }
1003
1004 scan = SCAN_PAGE;
1005
1006 if (cp->val)
1007 scan |= SCAN_INQUIRY;
1008 else
1009 cancel_delayed_work(&hdev->discov_off);
1010
1011 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1012 if (err < 0)
1013 mgmt_pending_remove(cmd);
1014
Johan Hedberg03811012010-12-08 00:21:06 +02001015 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001016 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001017
1018failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001019 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001020 return err;
1021}
1022
Johan Hedberg406d7802013-03-15 17:07:09 -05001023static void write_fast_connectable(struct hci_request *req, bool enable)
1024{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001025 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001026 struct hci_cp_write_page_scan_activity acp;
1027 u8 type;
1028
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001029 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1030 return;
1031
Johan Hedberg406d7802013-03-15 17:07:09 -05001032 if (enable) {
1033 type = PAGE_SCAN_TYPE_INTERLACED;
1034
1035 /* 160 msec page scan interval */
1036 acp.interval = __constant_cpu_to_le16(0x0100);
1037 } else {
1038 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1039
1040 /* default 1.28 sec page scan */
1041 acp.interval = __constant_cpu_to_le16(0x0800);
1042 }
1043
1044 acp.window = __constant_cpu_to_le16(0x0012);
1045
Johan Hedbergbd98b992013-03-15 17:07:13 -05001046 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1047 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1048 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1049 sizeof(acp), &acp);
1050
1051 if (hdev->page_scan_type != type)
1052 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001053}
1054
Johan Hedberg2b76f452013-03-15 17:07:04 -05001055static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1056{
1057 struct pending_cmd *cmd;
1058
1059 BT_DBG("status 0x%02x", status);
1060
1061 hci_dev_lock(hdev);
1062
1063 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1064 if (!cmd)
1065 goto unlock;
1066
1067 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1068
1069 mgmt_pending_remove(cmd);
1070
1071unlock:
1072 hci_dev_unlock(hdev);
1073}
1074
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001075static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001076 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001077{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001078 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001079 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001080 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001081 u8 scan;
1082 int err;
1083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001084 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001085
Johan Hedberg33c525c2012-10-24 21:11:58 +03001086 if (!lmp_bredr_capable(hdev))
1087 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1088 MGMT_STATUS_NOT_SUPPORTED);
1089
Johan Hedberga7e80f22013-01-09 16:05:19 +02001090 if (cp->val != 0x00 && cp->val != 0x01)
1091 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1092 MGMT_STATUS_INVALID_PARAMS);
1093
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001094 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001095
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001096 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001097 bool changed = false;
1098
1099 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1100 changed = true;
1101
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001102 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001103 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001104 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001105 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1106 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1107 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001108
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001109 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001110 if (err < 0)
1111 goto failed;
1112
1113 if (changed)
1114 err = new_settings(hdev, sk);
1115
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001116 goto failed;
1117 }
1118
1119 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001120 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001121 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001122 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001123 goto failed;
1124 }
1125
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001126 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001127 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001128 goto failed;
1129 }
1130
1131 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1132 if (!cmd) {
1133 err = -ENOMEM;
1134 goto failed;
1135 }
1136
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001137 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001138 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001139 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001140 scan = 0;
1141
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001142 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001143 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001144 cancel_delayed_work(&hdev->discov_off);
1145 }
1146
Johan Hedberg2b76f452013-03-15 17:07:04 -05001147 hci_req_init(&req, hdev);
1148
1149 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1150
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001151 /* If we're going from non-connectable to connectable or
1152 * vice-versa when fast connectable is enabled ensure that fast
1153 * connectable gets disabled. write_fast_connectable won't do
1154 * anything if the page scan parameters are already what they
1155 * should be.
1156 */
1157 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001158 write_fast_connectable(&req, false);
1159
Johan Hedberg2b76f452013-03-15 17:07:04 -05001160 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001161 if (err < 0)
1162 mgmt_pending_remove(cmd);
1163
1164failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001165 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001166 return err;
1167}
1168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001169static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001170 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001171{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001172 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001173 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001175 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001176
Johan Hedberga7e80f22013-01-09 16:05:19 +02001177 if (cp->val != 0x00 && cp->val != 0x01)
1178 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1179 MGMT_STATUS_INVALID_PARAMS);
1180
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001181 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001182
1183 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001184 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001185 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001186 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001188 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001189 if (err < 0)
1190 goto failed;
1191
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001192 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193
1194failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001195 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196 return err;
1197}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001198
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001199static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1200 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001201{
1202 struct mgmt_mode *cp = data;
1203 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001204 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001205 int err;
1206
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001207 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001208
Johan Hedberg33c525c2012-10-24 21:11:58 +03001209 if (!lmp_bredr_capable(hdev))
1210 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1211 MGMT_STATUS_NOT_SUPPORTED);
1212
Johan Hedberga7e80f22013-01-09 16:05:19 +02001213 if (cp->val != 0x00 && cp->val != 0x01)
1214 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1215 MGMT_STATUS_INVALID_PARAMS);
1216
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001217 hci_dev_lock(hdev);
1218
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001219 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001220 bool changed = false;
1221
1222 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001223 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001224 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1225 changed = true;
1226 }
1227
1228 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1229 if (err < 0)
1230 goto failed;
1231
1232 if (changed)
1233 err = new_settings(hdev, sk);
1234
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001235 goto failed;
1236 }
1237
1238 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001239 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001240 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001241 goto failed;
1242 }
1243
1244 val = !!cp->val;
1245
1246 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1247 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1248 goto failed;
1249 }
1250
1251 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1252 if (!cmd) {
1253 err = -ENOMEM;
1254 goto failed;
1255 }
1256
1257 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1258 if (err < 0) {
1259 mgmt_pending_remove(cmd);
1260 goto failed;
1261 }
1262
1263failed:
1264 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001265 return err;
1266}
1267
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001268static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001269{
1270 struct mgmt_mode *cp = data;
1271 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001272 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001273 int err;
1274
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001275 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001276
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001277 if (!lmp_ssp_capable(hdev))
1278 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1279 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001280
Johan Hedberga7e80f22013-01-09 16:05:19 +02001281 if (cp->val != 0x00 && cp->val != 0x01)
1282 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1283 MGMT_STATUS_INVALID_PARAMS);
1284
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001285 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001286
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001287 val = !!cp->val;
1288
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001289 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001290 bool changed = false;
1291
1292 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1293 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1294 changed = true;
1295 }
1296
1297 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1298 if (err < 0)
1299 goto failed;
1300
1301 if (changed)
1302 err = new_settings(hdev, sk);
1303
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001304 goto failed;
1305 }
1306
1307 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001308 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1309 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001310 goto failed;
1311 }
1312
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001313 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1314 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1315 goto failed;
1316 }
1317
1318 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1319 if (!cmd) {
1320 err = -ENOMEM;
1321 goto failed;
1322 }
1323
1324 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1325 if (err < 0) {
1326 mgmt_pending_remove(cmd);
1327 goto failed;
1328 }
1329
1330failed:
1331 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001332 return err;
1333}
1334
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001335static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001336{
1337 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001338
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001339 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001340
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001341 if (!enable_hs)
1342 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001344
Johan Hedberga7e80f22013-01-09 16:05:19 +02001345 if (cp->val != 0x00 && cp->val != 0x01)
1346 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1347 MGMT_STATUS_INVALID_PARAMS);
1348
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001349 if (cp->val)
1350 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1351 else
1352 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001354 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001355}
1356
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001357static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001358{
1359 struct mgmt_mode *cp = data;
1360 struct hci_cp_write_le_host_supported hci_cp;
1361 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001362 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001363 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001364
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001365 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001366
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001367 if (!lmp_le_capable(hdev))
1368 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1369 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001370
Johan Hedberga7e80f22013-01-09 16:05:19 +02001371 if (cp->val != 0x00 && cp->val != 0x01)
1372 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1373 MGMT_STATUS_INVALID_PARAMS);
1374
Johan Hedbergc73eee92013-04-19 18:35:21 +03001375 /* LE-only devices do not allow toggling LE on/off */
1376 if (!lmp_bredr_capable(hdev))
1377 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1378 MGMT_STATUS_REJECTED);
1379
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001380 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001381
1382 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001383 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001384
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001385 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001386 bool changed = false;
1387
1388 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1389 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1390 changed = true;
1391 }
1392
1393 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1394 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001395 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001396
1397 if (changed)
1398 err = new_settings(hdev, sk);
1399
Johan Hedberg1de028c2012-02-29 19:55:35 -08001400 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001401 }
1402
1403 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001404 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001405 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001406 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001407 }
1408
1409 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1410 if (!cmd) {
1411 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001412 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001413 }
1414
1415 memset(&hci_cp, 0, sizeof(hci_cp));
1416
1417 if (val) {
1418 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001419 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001420 }
1421
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001422 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1423 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301424 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001425 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001426
Johan Hedberg1de028c2012-02-29 19:55:35 -08001427unlock:
1428 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001429 return err;
1430}
1431
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001432/* This is a helper function to test for pending mgmt commands that can
1433 * cause CoD or EIR HCI commands. We can only allow one such pending
1434 * mgmt command at a time since otherwise we cannot easily track what
1435 * the current values are, will be, and based on that calculate if a new
1436 * HCI command needs to be sent and if yes with what value.
1437 */
1438static bool pending_eir_or_class(struct hci_dev *hdev)
1439{
1440 struct pending_cmd *cmd;
1441
1442 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1443 switch (cmd->opcode) {
1444 case MGMT_OP_ADD_UUID:
1445 case MGMT_OP_REMOVE_UUID:
1446 case MGMT_OP_SET_DEV_CLASS:
1447 case MGMT_OP_SET_POWERED:
1448 return true;
1449 }
1450 }
1451
1452 return false;
1453}
1454
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001455static const u8 bluetooth_base_uuid[] = {
1456 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1457 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1458};
1459
1460static u8 get_uuid_size(const u8 *uuid)
1461{
1462 u32 val;
1463
1464 if (memcmp(uuid, bluetooth_base_uuid, 12))
1465 return 128;
1466
1467 val = get_unaligned_le32(&uuid[12]);
1468 if (val > 0xffff)
1469 return 32;
1470
1471 return 16;
1472}
1473
Johan Hedberg92da6092013-03-15 17:06:55 -05001474static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1475{
1476 struct pending_cmd *cmd;
1477
1478 hci_dev_lock(hdev);
1479
1480 cmd = mgmt_pending_find(mgmt_op, hdev);
1481 if (!cmd)
1482 goto unlock;
1483
1484 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1485 hdev->dev_class, 3);
1486
1487 mgmt_pending_remove(cmd);
1488
1489unlock:
1490 hci_dev_unlock(hdev);
1491}
1492
1493static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1494{
1495 BT_DBG("status 0x%02x", status);
1496
1497 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1498}
1499
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001500static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001501{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001502 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001503 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001504 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001505 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001506 int err;
1507
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001508 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001509
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001510 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001511
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001512 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001513 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001514 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001515 goto failed;
1516 }
1517
Andre Guedes92c4c202012-06-07 19:05:44 -03001518 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001519 if (!uuid) {
1520 err = -ENOMEM;
1521 goto failed;
1522 }
1523
1524 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001525 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001526 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001527
Johan Hedbergde66aa62013-01-27 00:31:27 +02001528 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001529
Johan Hedberg890ea892013-03-15 17:06:52 -05001530 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001531
Johan Hedberg890ea892013-03-15 17:06:52 -05001532 update_class(&req);
1533 update_eir(&req);
1534
Johan Hedberg92da6092013-03-15 17:06:55 -05001535 err = hci_req_run(&req, add_uuid_complete);
1536 if (err < 0) {
1537 if (err != -ENODATA)
1538 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001539
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001540 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001541 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001542 goto failed;
1543 }
1544
1545 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001546 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001547 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001548 goto failed;
1549 }
1550
1551 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001552
1553failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001554 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001555 return err;
1556}
1557
Johan Hedberg24b78d02012-02-23 23:24:30 +02001558static bool enable_service_cache(struct hci_dev *hdev)
1559{
1560 if (!hdev_is_powered(hdev))
1561 return false;
1562
1563 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001564 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1565 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001566 return true;
1567 }
1568
1569 return false;
1570}
1571
Johan Hedberg92da6092013-03-15 17:06:55 -05001572static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1573{
1574 BT_DBG("status 0x%02x", status);
1575
1576 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1577}
1578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001579static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001580 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001581{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001582 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001583 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001584 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001585 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 -05001586 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001587 int err, found;
1588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001589 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001590
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001591 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001592
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001593 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001594 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001595 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001596 goto unlock;
1597 }
1598
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001599 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1600 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001601
Johan Hedberg24b78d02012-02-23 23:24:30 +02001602 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001603 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001604 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001605 goto unlock;
1606 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001607
Johan Hedberg9246a862012-02-23 21:33:16 +02001608 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001609 }
1610
1611 found = 0;
1612
Johan Hedberg056341c2013-01-27 00:31:30 +02001613 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001614 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1615 continue;
1616
1617 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001618 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001619 found++;
1620 }
1621
1622 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001623 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001624 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625 goto unlock;
1626 }
1627
Johan Hedberg9246a862012-02-23 21:33:16 +02001628update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001629 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001630
Johan Hedberg890ea892013-03-15 17:06:52 -05001631 update_class(&req);
1632 update_eir(&req);
1633
Johan Hedberg92da6092013-03-15 17:06:55 -05001634 err = hci_req_run(&req, remove_uuid_complete);
1635 if (err < 0) {
1636 if (err != -ENODATA)
1637 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001638
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001639 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001640 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001641 goto unlock;
1642 }
1643
1644 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001645 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001646 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001647 goto unlock;
1648 }
1649
1650 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001651
1652unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001653 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001654 return err;
1655}
1656
Johan Hedberg92da6092013-03-15 17:06:55 -05001657static void set_class_complete(struct hci_dev *hdev, u8 status)
1658{
1659 BT_DBG("status 0x%02x", status);
1660
1661 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1662}
1663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001664static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001665 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001666{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001667 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001668 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001669 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001670 int err;
1671
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001672 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001673
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001674 if (!lmp_bredr_capable(hdev))
1675 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1676 MGMT_STATUS_NOT_SUPPORTED);
1677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001678 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001679
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001680 if (pending_eir_or_class(hdev)) {
1681 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1682 MGMT_STATUS_BUSY);
1683 goto unlock;
1684 }
1685
1686 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1687 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1688 MGMT_STATUS_INVALID_PARAMS);
1689 goto unlock;
1690 }
1691
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001692 hdev->major_class = cp->major;
1693 hdev->minor_class = cp->minor;
1694
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001695 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001696 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001697 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001698 goto unlock;
1699 }
1700
Johan Hedberg890ea892013-03-15 17:06:52 -05001701 hci_req_init(&req, hdev);
1702
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001703 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001704 hci_dev_unlock(hdev);
1705 cancel_delayed_work_sync(&hdev->service_cache);
1706 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001707 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001708 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001709
Johan Hedberg890ea892013-03-15 17:06:52 -05001710 update_class(&req);
1711
Johan Hedberg92da6092013-03-15 17:06:55 -05001712 err = hci_req_run(&req, set_class_complete);
1713 if (err < 0) {
1714 if (err != -ENODATA)
1715 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001717 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001718 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001719 goto unlock;
1720 }
1721
1722 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001723 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001724 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001725 goto unlock;
1726 }
1727
1728 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001729
Johan Hedbergb5235a62012-02-21 14:32:24 +02001730unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001731 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001732 return err;
1733}
1734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001736 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001737{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001738 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001739 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001740 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001741
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001742 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001743
Johan Hedberg86742e12011-11-07 23:13:38 +02001744 expected_len = sizeof(*cp) + key_count *
1745 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001746 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001747 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001748 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001749 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001751 }
1752
Johan Hedberg4ae14302013-01-20 14:27:13 +02001753 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1754 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1755 MGMT_STATUS_INVALID_PARAMS);
1756
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001757 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001758 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001759
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001760 for (i = 0; i < key_count; i++) {
1761 struct mgmt_link_key_info *key = &cp->keys[i];
1762
1763 if (key->addr.type != BDADDR_BREDR)
1764 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1765 MGMT_STATUS_INVALID_PARAMS);
1766 }
1767
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001768 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001769
1770 hci_link_keys_clear(hdev);
1771
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001772 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001773 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001774 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001775 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001776
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001777 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001778 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001779
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001780 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001781 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001782 }
1783
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001784 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001785
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001786 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001787
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001788 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001789}
1790
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001791static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001792 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001793{
1794 struct mgmt_ev_device_unpaired ev;
1795
1796 bacpy(&ev.addr.bdaddr, bdaddr);
1797 ev.addr.type = addr_type;
1798
1799 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001800 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001801}
1802
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001803static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001804 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001805{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001806 struct mgmt_cp_unpair_device *cp = data;
1807 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001808 struct hci_cp_disconnect dc;
1809 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001810 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001811 int err;
1812
Johan Hedberga8a1d192011-11-10 15:54:38 +02001813 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001814 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1815 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001816
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001817 if (!bdaddr_type_is_valid(cp->addr.type))
1818 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1819 MGMT_STATUS_INVALID_PARAMS,
1820 &rp, sizeof(rp));
1821
Johan Hedberg118da702013-01-20 14:27:20 +02001822 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1823 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1824 MGMT_STATUS_INVALID_PARAMS,
1825 &rp, sizeof(rp));
1826
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001827 hci_dev_lock(hdev);
1828
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001829 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001830 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001831 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001832 goto unlock;
1833 }
1834
Andre Guedes591f47f2012-04-24 21:02:49 -03001835 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001836 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1837 else
1838 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001839
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001840 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001843 goto unlock;
1844 }
1845
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001846 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001847 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001848 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001849 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001850 else
1851 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001852 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001853 } else {
1854 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001855 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001856
Johan Hedberga8a1d192011-11-10 15:54:38 +02001857 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001858 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001859 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001860 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001861 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001862 }
1863
Johan Hedberg124f6e32012-02-09 13:50:12 +02001864 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001865 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001866 if (!cmd) {
1867 err = -ENOMEM;
1868 goto unlock;
1869 }
1870
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001871 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001872 dc.reason = 0x13; /* Remote User Terminated Connection */
1873 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1874 if (err < 0)
1875 mgmt_pending_remove(cmd);
1876
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001877unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001878 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879 return err;
1880}
1881
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001882static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001883 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001884{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001885 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001886 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001887 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001888 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001889 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001890 int err;
1891
1892 BT_DBG("");
1893
Johan Hedberg06a63b12013-01-20 14:27:21 +02001894 memset(&rp, 0, sizeof(rp));
1895 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1896 rp.addr.type = cp->addr.type;
1897
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001898 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001899 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1900 MGMT_STATUS_INVALID_PARAMS,
1901 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001902
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001903 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001904
1905 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001906 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1907 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001908 goto failed;
1909 }
1910
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001911 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001912 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1913 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001914 goto failed;
1915 }
1916
Andre Guedes591f47f2012-04-24 21:02:49 -03001917 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001918 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1919 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001920 else
1921 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001922
Vishal Agarwalf9607272012-06-13 05:32:43 +05301923 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001924 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1925 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001926 goto failed;
1927 }
1928
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001929 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001930 if (!cmd) {
1931 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001932 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001933 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001934
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001935 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001936 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001937
1938 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1939 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001940 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001941
1942failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001943 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001944 return err;
1945}
1946
Andre Guedes57c14772012-04-24 21:02:50 -03001947static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001948{
1949 switch (link_type) {
1950 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001951 switch (addr_type) {
1952 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001953 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001954
Johan Hedberg48264f02011-11-09 13:58:58 +02001955 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001956 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001957 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001958 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001959
Johan Hedberg4c659c32011-11-07 23:13:39 +02001960 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001961 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001962 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001963 }
1964}
1965
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001966static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1967 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001968{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001969 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001970 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001971 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001972 int err;
1973 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001974
1975 BT_DBG("");
1976
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001977 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001978
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001979 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001980 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001981 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001982 goto unlock;
1983 }
1984
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001985 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001986 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1987 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001988 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001989 }
1990
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001991 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001992 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001993 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001994 err = -ENOMEM;
1995 goto unlock;
1996 }
1997
Johan Hedberg2784eb42011-01-21 13:56:35 +02001998 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001999 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002000 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2001 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002002 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002003 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002004 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002005 continue;
2006 i++;
2007 }
2008
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002009 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002010
Johan Hedberg4c659c32011-11-07 23:13:39 +02002011 /* Recalculate length in case of filtered SCO connections, etc */
2012 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002016
Johan Hedberga38528f2011-01-22 06:46:43 +02002017 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002018
2019unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002020 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002021 return err;
2022}
2023
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002024static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002025 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002026{
2027 struct pending_cmd *cmd;
2028 int err;
2029
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002030 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002031 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002032 if (!cmd)
2033 return -ENOMEM;
2034
Johan Hedbergd8457692012-02-17 14:24:57 +02002035 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002036 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002037 if (err < 0)
2038 mgmt_pending_remove(cmd);
2039
2040 return err;
2041}
2042
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002043static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002044 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002045{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002046 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002047 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002048 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002049 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002050 int err;
2051
2052 BT_DBG("");
2053
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002054 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002055
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002056 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002057 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002058 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002059 goto failed;
2060 }
2061
Johan Hedbergd8457692012-02-17 14:24:57 +02002062 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002063 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002064 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002065 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002066 goto failed;
2067 }
2068
2069 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002070 struct mgmt_cp_pin_code_neg_reply ncp;
2071
2072 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002073
2074 BT_ERR("PIN code is not 16 bytes long");
2075
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002076 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002077 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002078 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002080
2081 goto failed;
2082 }
2083
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002084 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002085 if (!cmd) {
2086 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002087 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002088 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002089
Johan Hedbergd8457692012-02-17 14:24:57 +02002090 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002091 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002092 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002093
2094 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2095 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002096 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002097
2098failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002099 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002100 return err;
2101}
2102
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002103static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2104 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002105{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002106 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002107
2108 BT_DBG("");
2109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002110 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002111
2112 hdev->io_capability = cp->io_capability;
2113
2114 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002115 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002116
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002117 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002118
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002119 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2120 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002121}
2122
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002123static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002124{
2125 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002126 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002127
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002128 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002129 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2130 continue;
2131
Johan Hedberge9a416b2011-02-19 12:05:56 -03002132 if (cmd->user_data != conn)
2133 continue;
2134
2135 return cmd;
2136 }
2137
2138 return NULL;
2139}
2140
2141static void pairing_complete(struct pending_cmd *cmd, u8 status)
2142{
2143 struct mgmt_rp_pair_device rp;
2144 struct hci_conn *conn = cmd->user_data;
2145
Johan Hedbergba4e5642011-11-11 00:07:34 +02002146 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002147 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002148
Johan Hedbergaee9b212012-02-18 15:07:59 +02002149 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002150 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002151
2152 /* So we don't get further callbacks for this connection */
2153 conn->connect_cfm_cb = NULL;
2154 conn->security_cfm_cb = NULL;
2155 conn->disconn_cfm_cb = NULL;
2156
David Herrmann76a68ba2013-04-06 20:28:37 +02002157 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002158
Johan Hedberga664b5b2011-02-19 12:06:02 -03002159 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002160}
2161
2162static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2163{
2164 struct pending_cmd *cmd;
2165
2166 BT_DBG("status %u", status);
2167
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002168 cmd = find_pairing(conn);
2169 if (!cmd)
2170 BT_DBG("Unable to find a pending command");
2171 else
Johan Hedberge2113262012-02-18 15:20:03 +02002172 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002173}
2174
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302175static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2176{
2177 struct pending_cmd *cmd;
2178
2179 BT_DBG("status %u", status);
2180
2181 if (!status)
2182 return;
2183
2184 cmd = find_pairing(conn);
2185 if (!cmd)
2186 BT_DBG("Unable to find a pending command");
2187 else
2188 pairing_complete(cmd, mgmt_status(status));
2189}
2190
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002191static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002192 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002193{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002194 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002195 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002196 struct pending_cmd *cmd;
2197 u8 sec_level, auth_type;
2198 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002199 int err;
2200
2201 BT_DBG("");
2202
Szymon Jancf950a30e2013-01-18 12:48:07 +01002203 memset(&rp, 0, sizeof(rp));
2204 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2205 rp.addr.type = cp->addr.type;
2206
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002207 if (!bdaddr_type_is_valid(cp->addr.type))
2208 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2209 MGMT_STATUS_INVALID_PARAMS,
2210 &rp, sizeof(rp));
2211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002212 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002213
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002214 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002215 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2216 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002217 goto unlock;
2218 }
2219
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002220 sec_level = BT_SECURITY_MEDIUM;
2221 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002222 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002223 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002224 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002225
Andre Guedes591f47f2012-04-24 21:02:49 -03002226 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002227 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2228 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002229 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002230 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2231 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002232
Ville Tervo30e76272011-02-22 16:10:53 -03002233 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002234 int status;
2235
2236 if (PTR_ERR(conn) == -EBUSY)
2237 status = MGMT_STATUS_BUSY;
2238 else
2239 status = MGMT_STATUS_CONNECT_FAILED;
2240
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002241 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002242 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002243 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002244 goto unlock;
2245 }
2246
2247 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002248 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002249 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002250 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002251 goto unlock;
2252 }
2253
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002254 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002255 if (!cmd) {
2256 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002257 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002258 goto unlock;
2259 }
2260
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002261 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002262 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002263 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302264 else
2265 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002266
Johan Hedberge9a416b2011-02-19 12:05:56 -03002267 conn->security_cfm_cb = pairing_complete_cb;
2268 conn->disconn_cfm_cb = pairing_complete_cb;
2269 conn->io_capability = cp->io_cap;
2270 cmd->user_data = conn;
2271
2272 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002273 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002274 pairing_complete(cmd, 0);
2275
2276 err = 0;
2277
2278unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002279 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002280 return err;
2281}
2282
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002283static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2284 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002285{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002286 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002287 struct pending_cmd *cmd;
2288 struct hci_conn *conn;
2289 int err;
2290
2291 BT_DBG("");
2292
Johan Hedberg28424702012-02-02 04:02:29 +02002293 hci_dev_lock(hdev);
2294
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002295 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002296 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002297 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002298 goto unlock;
2299 }
2300
Johan Hedberg28424702012-02-02 04:02:29 +02002301 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2302 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002303 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002305 goto unlock;
2306 }
2307
2308 conn = cmd->user_data;
2309
2310 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002311 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002312 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002313 goto unlock;
2314 }
2315
2316 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2317
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002318 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002319 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002320unlock:
2321 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002322 return err;
2323}
2324
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002325static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002326 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002327 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002328{
Johan Hedberga5c29682011-02-19 12:05:57 -03002329 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002330 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002331 int err;
2332
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002333 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002334
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002335 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002336 err = cmd_complete(sk, hdev->id, mgmt_op,
2337 MGMT_STATUS_NOT_POWERED, addr,
2338 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002339 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002340 }
2341
Johan Hedberg1707c602013-03-15 17:07:15 -05002342 if (addr->type == BDADDR_BREDR)
2343 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002344 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002345 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002346
Johan Hedberg272d90d2012-02-09 15:26:12 +02002347 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002348 err = cmd_complete(sk, hdev->id, mgmt_op,
2349 MGMT_STATUS_NOT_CONNECTED, addr,
2350 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002351 goto done;
2352 }
2353
Johan Hedberg1707c602013-03-15 17:07:15 -05002354 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002355 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002356 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002357
Brian Gix5fe57d92011-12-21 16:12:13 -08002358 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002359 err = cmd_complete(sk, hdev->id, mgmt_op,
2360 MGMT_STATUS_SUCCESS, addr,
2361 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002362 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002363 err = cmd_complete(sk, hdev->id, mgmt_op,
2364 MGMT_STATUS_FAILED, addr,
2365 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002366
Brian Gix47c15e22011-11-16 13:53:14 -08002367 goto done;
2368 }
2369
Johan Hedberg1707c602013-03-15 17:07:15 -05002370 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002371 if (!cmd) {
2372 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002373 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002374 }
2375
Brian Gix0df4c182011-11-16 13:53:13 -08002376 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002377 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2378 struct hci_cp_user_passkey_reply cp;
2379
Johan Hedberg1707c602013-03-15 17:07:15 -05002380 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002381 cp.passkey = passkey;
2382 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2383 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002384 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2385 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002386
Johan Hedberga664b5b2011-02-19 12:06:02 -03002387 if (err < 0)
2388 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002389
Brian Gix0df4c182011-11-16 13:53:13 -08002390done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002391 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002392 return err;
2393}
2394
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302395static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2396 void *data, u16 len)
2397{
2398 struct mgmt_cp_pin_code_neg_reply *cp = data;
2399
2400 BT_DBG("");
2401
Johan Hedberg1707c602013-03-15 17:07:15 -05002402 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302403 MGMT_OP_PIN_CODE_NEG_REPLY,
2404 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2405}
2406
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002407static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2408 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002409{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002410 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002411
2412 BT_DBG("");
2413
2414 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002415 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002416 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002417
Johan Hedberg1707c602013-03-15 17:07:15 -05002418 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002419 MGMT_OP_USER_CONFIRM_REPLY,
2420 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002421}
2422
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002423static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002424 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002425{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002426 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002427
2428 BT_DBG("");
2429
Johan Hedberg1707c602013-03-15 17:07:15 -05002430 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002431 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2432 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002433}
2434
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2436 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002437{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002438 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002439
2440 BT_DBG("");
2441
Johan Hedberg1707c602013-03-15 17:07:15 -05002442 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002443 MGMT_OP_USER_PASSKEY_REPLY,
2444 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002445}
2446
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002447static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002448 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002449{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002450 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002451
2452 BT_DBG("");
2453
Johan Hedberg1707c602013-03-15 17:07:15 -05002454 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2456 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002457}
2458
Johan Hedberg13928972013-03-15 17:07:00 -05002459static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002460{
Johan Hedberg13928972013-03-15 17:07:00 -05002461 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002462 struct hci_cp_write_local_name cp;
2463
Johan Hedberg13928972013-03-15 17:07:00 -05002464 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002465
Johan Hedberg890ea892013-03-15 17:06:52 -05002466 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002467}
2468
Johan Hedberg13928972013-03-15 17:07:00 -05002469static void set_name_complete(struct hci_dev *hdev, u8 status)
2470{
2471 struct mgmt_cp_set_local_name *cp;
2472 struct pending_cmd *cmd;
2473
2474 BT_DBG("status 0x%02x", status);
2475
2476 hci_dev_lock(hdev);
2477
2478 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2479 if (!cmd)
2480 goto unlock;
2481
2482 cp = cmd->param;
2483
2484 if (status)
2485 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2486 mgmt_status(status));
2487 else
2488 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2489 cp, sizeof(*cp));
2490
2491 mgmt_pending_remove(cmd);
2492
2493unlock:
2494 hci_dev_unlock(hdev);
2495}
2496
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002497static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002498 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002499{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002500 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002501 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002502 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002503 int err;
2504
2505 BT_DBG("");
2506
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002507 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002508
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002509 /* If the old values are the same as the new ones just return a
2510 * direct command complete event.
2511 */
2512 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2513 !memcmp(hdev->short_name, cp->short_name,
2514 sizeof(hdev->short_name))) {
2515 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2516 data, len);
2517 goto failed;
2518 }
2519
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002520 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002521
Johan Hedbergb5235a62012-02-21 14:32:24 +02002522 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002523 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002524
2525 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002526 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002527 if (err < 0)
2528 goto failed;
2529
2530 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002531 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002532
Johan Hedbergb5235a62012-02-21 14:32:24 +02002533 goto failed;
2534 }
2535
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002536 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002537 if (!cmd) {
2538 err = -ENOMEM;
2539 goto failed;
2540 }
2541
Johan Hedberg13928972013-03-15 17:07:00 -05002542 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2543
Johan Hedberg890ea892013-03-15 17:06:52 -05002544 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002545
2546 if (lmp_bredr_capable(hdev)) {
2547 update_name(&req);
2548 update_eir(&req);
2549 }
2550
2551 if (lmp_le_capable(hdev))
2552 hci_update_ad(&req);
2553
Johan Hedberg13928972013-03-15 17:07:00 -05002554 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002555 if (err < 0)
2556 mgmt_pending_remove(cmd);
2557
2558failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002559 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002560 return err;
2561}
2562
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002563static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002564 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002565{
Szymon Jancc35938b2011-03-22 13:12:21 +01002566 struct pending_cmd *cmd;
2567 int err;
2568
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002569 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002570
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002571 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002572
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002573 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002574 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002575 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002576 goto unlock;
2577 }
2578
Andre Guedes9a1a1992012-07-24 15:03:48 -03002579 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002580 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002581 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002582 goto unlock;
2583 }
2584
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002585 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002586 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002587 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002588 goto unlock;
2589 }
2590
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002591 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002592 if (!cmd) {
2593 err = -ENOMEM;
2594 goto unlock;
2595 }
2596
2597 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2598 if (err < 0)
2599 mgmt_pending_remove(cmd);
2600
2601unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002602 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002603 return err;
2604}
2605
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002606static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002607 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002608{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002609 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002610 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002611 int err;
2612
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002613 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002614
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002615 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002616
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002617 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002618 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002619 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002620 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002621 else
Szymon Janca6785be2012-12-13 15:11:21 +01002622 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002624 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002625 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002626
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002627 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002628 return err;
2629}
2630
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002631static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002632 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002633{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002634 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002635 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002636 int err;
2637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002638 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002640 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002641
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002642 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002643 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002644 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002645 else
Szymon Janca6785be2012-12-13 15:11:21 +01002646 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002650
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002651 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002652 return err;
2653}
2654
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002655static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2656{
2657 struct pending_cmd *cmd;
2658 u8 type;
2659 int err;
2660
2661 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2662
2663 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2664 if (!cmd)
2665 return -ENOENT;
2666
2667 type = hdev->discovery.type;
2668
2669 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2670 &type, sizeof(type));
2671 mgmt_pending_remove(cmd);
2672
2673 return err;
2674}
2675
Andre Guedes7c307722013-04-30 15:29:28 -03002676static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2677{
2678 BT_DBG("status %d", status);
2679
2680 if (status) {
2681 hci_dev_lock(hdev);
2682 mgmt_start_discovery_failed(hdev, status);
2683 hci_dev_unlock(hdev);
2684 return;
2685 }
2686
2687 hci_dev_lock(hdev);
2688 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2689 hci_dev_unlock(hdev);
2690
2691 switch (hdev->discovery.type) {
2692 case DISCOV_TYPE_LE:
2693 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002694 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002695 break;
2696
2697 case DISCOV_TYPE_INTERLEAVED:
2698 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002699 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002700 break;
2701
2702 case DISCOV_TYPE_BREDR:
2703 break;
2704
2705 default:
2706 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2707 }
2708}
2709
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002712{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002713 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002714 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002715 struct hci_cp_le_set_scan_param param_cp;
2716 struct hci_cp_le_set_scan_enable enable_cp;
2717 struct hci_cp_inquiry inq_cp;
2718 struct hci_request req;
2719 /* General inquiry access code (GIAC) */
2720 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberg14a53662011-04-27 10:29:56 -04002721 int err;
2722
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002723 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002724
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002725 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002726
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002727 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002728 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002729 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002730 goto failed;
2731 }
2732
Andre Guedes642be6c2012-03-21 00:03:37 -03002733 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2734 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2735 MGMT_STATUS_BUSY);
2736 goto failed;
2737 }
2738
Johan Hedbergff9ef572012-01-04 14:23:45 +02002739 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002740 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002741 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002742 goto failed;
2743 }
2744
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002745 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002746 if (!cmd) {
2747 err = -ENOMEM;
2748 goto failed;
2749 }
2750
Andre Guedes4aab14e2012-02-17 20:39:36 -03002751 hdev->discovery.type = cp->type;
2752
Andre Guedes7c307722013-04-30 15:29:28 -03002753 hci_req_init(&req, hdev);
2754
Andre Guedes4aab14e2012-02-17 20:39:36 -03002755 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002756 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002757 if (!lmp_bredr_capable(hdev)) {
2758 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2759 MGMT_STATUS_NOT_SUPPORTED);
2760 mgmt_pending_remove(cmd);
2761 goto failed;
2762 }
2763
Andre Guedes7c307722013-04-30 15:29:28 -03002764 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2765 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2766 MGMT_STATUS_BUSY);
2767 mgmt_pending_remove(cmd);
2768 goto failed;
2769 }
2770
2771 hci_inquiry_cache_flush(hdev);
2772
2773 memset(&inq_cp, 0, sizeof(inq_cp));
2774 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002775 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002776 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002777 break;
2778
2779 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002780 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg757aee02013-04-24 13:05:32 +03002781 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002782 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2783 MGMT_STATUS_NOT_SUPPORTED);
2784 mgmt_pending_remove(cmd);
2785 goto failed;
2786 }
2787
Andre Guedes7c307722013-04-30 15:29:28 -03002788 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
2789 !lmp_bredr_capable(hdev)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002790 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2791 MGMT_STATUS_NOT_SUPPORTED);
2792 mgmt_pending_remove(cmd);
2793 goto failed;
2794 }
2795
Andre Guedes7c307722013-04-30 15:29:28 -03002796 if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags)) {
2797 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2798 MGMT_STATUS_REJECTED);
2799 mgmt_pending_remove(cmd);
2800 goto failed;
2801 }
2802
2803 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2804 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2805 MGMT_STATUS_BUSY);
2806 mgmt_pending_remove(cmd);
2807 goto failed;
2808 }
2809
2810 memset(&param_cp, 0, sizeof(param_cp));
2811 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002812 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2813 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Andre Guedes7c307722013-04-30 15:29:28 -03002814 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2815 &param_cp);
2816
2817 memset(&enable_cp, 0, sizeof(enable_cp));
2818 enable_cp.enable = LE_SCAN_ENABLE;
2819 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2820 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2821 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002822 break;
2823
Andre Guedesf39799f2012-02-17 20:39:35 -03002824 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002825 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2826 MGMT_STATUS_INVALID_PARAMS);
2827 mgmt_pending_remove(cmd);
2828 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002829 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002830
Andre Guedes7c307722013-04-30 15:29:28 -03002831 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002832 if (err < 0)
2833 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002834 else
2835 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002836
2837failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002838 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002839 return err;
2840}
2841
Andre Guedes1183fdc2013-04-30 15:29:35 -03002842static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2843{
2844 struct pending_cmd *cmd;
2845 int err;
2846
2847 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2848 if (!cmd)
2849 return -ENOENT;
2850
2851 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2852 &hdev->discovery.type, sizeof(hdev->discovery.type));
2853 mgmt_pending_remove(cmd);
2854
2855 return err;
2856}
2857
Andre Guedes0e05bba2013-04-30 15:29:33 -03002858static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2859{
2860 BT_DBG("status %d", status);
2861
2862 hci_dev_lock(hdev);
2863
2864 if (status) {
2865 mgmt_stop_discovery_failed(hdev, status);
2866 goto unlock;
2867 }
2868
2869 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2870
2871unlock:
2872 hci_dev_unlock(hdev);
2873}
2874
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002875static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002876 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002877{
Johan Hedbergd9306502012-02-20 23:25:18 +02002878 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002879 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002880 struct hci_cp_remote_name_req_cancel cp;
2881 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03002882 struct hci_request req;
2883 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04002884 int err;
2885
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002886 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002887
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002888 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002889
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002890 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002891 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002892 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2893 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002894 goto unlock;
2895 }
2896
2897 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002898 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002899 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2900 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002901 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002902 }
2903
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002904 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002905 if (!cmd) {
2906 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002907 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002908 }
2909
Andre Guedes0e05bba2013-04-30 15:29:33 -03002910 hci_req_init(&req, hdev);
2911
Andre Guedese0d9727e2012-03-20 15:15:36 -03002912 switch (hdev->discovery.state) {
2913 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03002914 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2915 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
2916 } else {
2917 cancel_delayed_work(&hdev->le_scan_disable);
2918
2919 memset(&enable_cp, 0, sizeof(enable_cp));
2920 enable_cp.enable = LE_SCAN_DISABLE;
2921 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
2922 sizeof(enable_cp), &enable_cp);
2923 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03002924
Andre Guedese0d9727e2012-03-20 15:15:36 -03002925 break;
2926
2927 case DISCOVERY_RESOLVING:
2928 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002929 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002930 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002931 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002932 err = cmd_complete(sk, hdev->id,
2933 MGMT_OP_STOP_DISCOVERY, 0,
2934 &mgmt_cp->type,
2935 sizeof(mgmt_cp->type));
2936 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2937 goto unlock;
2938 }
2939
2940 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002941 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2942 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002943
2944 break;
2945
2946 default:
2947 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03002948
2949 mgmt_pending_remove(cmd);
2950 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
2951 MGMT_STATUS_FAILED, &mgmt_cp->type,
2952 sizeof(mgmt_cp->type));
2953 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002954 }
2955
Andre Guedes0e05bba2013-04-30 15:29:33 -03002956 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002957 if (err < 0)
2958 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002959 else
2960 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002961
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002962unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002963 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002964 return err;
2965}
2966
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002967static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002968 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002969{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002970 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002971 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002972 int err;
2973
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002974 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002975
Johan Hedberg561aafb2012-01-04 13:31:59 +02002976 hci_dev_lock(hdev);
2977
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002978 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002979 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002980 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002981 goto failed;
2982 }
2983
Johan Hedberga198e7b2012-02-17 14:27:06 +02002984 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002985 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002986 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002987 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002988 goto failed;
2989 }
2990
2991 if (cp->name_known) {
2992 e->name_state = NAME_KNOWN;
2993 list_del(&e->list);
2994 } else {
2995 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002996 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002997 }
2998
Johan Hedberge3846622013-01-09 15:29:33 +02002999 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3000 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003001
3002failed:
3003 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003004 return err;
3005}
3006
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003007static int block_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_block_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_BLOCK_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_add(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_FAILED;
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_BLOCK_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
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003037static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003039{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003040 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003041 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003042 int err;
3043
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003044 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003045
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003046 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003047 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3048 MGMT_STATUS_INVALID_PARAMS,
3049 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003050
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003051 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003052
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003053 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003054 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003055 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003056 else
Szymon Janca6785be2012-12-13 15:11:21 +01003057 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003058
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003059 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003060 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003061
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003062 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003063
3064 return err;
3065}
3066
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003067static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3068 u16 len)
3069{
3070 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003071 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003072 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003073 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003074
3075 BT_DBG("%s", hdev->name);
3076
Szymon Jancc72d4b82012-03-16 16:02:57 +01003077 source = __le16_to_cpu(cp->source);
3078
3079 if (source > 0x0002)
3080 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3081 MGMT_STATUS_INVALID_PARAMS);
3082
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003083 hci_dev_lock(hdev);
3084
Szymon Jancc72d4b82012-03-16 16:02:57 +01003085 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003086 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3087 hdev->devid_product = __le16_to_cpu(cp->product);
3088 hdev->devid_version = __le16_to_cpu(cp->version);
3089
3090 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3091
Johan Hedberg890ea892013-03-15 17:06:52 -05003092 hci_req_init(&req, hdev);
3093 update_eir(&req);
3094 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003095
3096 hci_dev_unlock(hdev);
3097
3098 return err;
3099}
3100
Johan Hedberg33e38b32013-03-15 17:07:05 -05003101static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3102{
3103 struct pending_cmd *cmd;
3104
3105 BT_DBG("status 0x%02x", status);
3106
3107 hci_dev_lock(hdev);
3108
3109 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3110 if (!cmd)
3111 goto unlock;
3112
3113 if (status) {
3114 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3115 mgmt_status(status));
3116 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003117 struct mgmt_mode *cp = cmd->param;
3118
3119 if (cp->val)
3120 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3121 else
3122 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3123
Johan Hedberg33e38b32013-03-15 17:07:05 -05003124 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3125 new_settings(hdev, cmd->sk);
3126 }
3127
3128 mgmt_pending_remove(cmd);
3129
3130unlock:
3131 hci_dev_unlock(hdev);
3132}
3133
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003134static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003135 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003136{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003137 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003138 struct pending_cmd *cmd;
3139 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003140 int err;
3141
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003142 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003143
Johan Hedberg1a47aee2013-03-15 17:07:06 -05003144 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003145 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3146 MGMT_STATUS_NOT_SUPPORTED);
3147
Johan Hedberga7e80f22013-01-09 16:05:19 +02003148 if (cp->val != 0x00 && cp->val != 0x01)
3149 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3150 MGMT_STATUS_INVALID_PARAMS);
3151
Johan Hedberg5400c042012-02-21 16:40:33 +02003152 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003153 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003154 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003155
3156 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003157 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003158 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003159
3160 hci_dev_lock(hdev);
3161
Johan Hedberg05cbf292013-03-15 17:07:07 -05003162 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3163 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3164 MGMT_STATUS_BUSY);
3165 goto unlock;
3166 }
3167
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003168 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3169 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3170 hdev);
3171 goto unlock;
3172 }
3173
Johan Hedberg33e38b32013-03-15 17:07:05 -05003174 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3175 data, len);
3176 if (!cmd) {
3177 err = -ENOMEM;
3178 goto unlock;
3179 }
3180
3181 hci_req_init(&req, hdev);
3182
Johan Hedberg406d7802013-03-15 17:07:09 -05003183 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003184
3185 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003186 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003187 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003188 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003189 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003190 }
3191
Johan Hedberg33e38b32013-03-15 17:07:05 -05003192unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003193 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003194
Antti Julkuf6422ec2011-06-22 13:11:56 +03003195 return err;
3196}
3197
Johan Hedberg3f706b72013-01-20 14:27:16 +02003198static bool ltk_is_valid(struct mgmt_ltk_info *key)
3199{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003200 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3201 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003202 if (key->master != 0x00 && key->master != 0x01)
3203 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003204 if (!bdaddr_type_is_le(key->addr.type))
3205 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003206 return true;
3207}
3208
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003209static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003210 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003211{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003212 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3213 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003214 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003215
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003216 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003217
3218 expected_len = sizeof(*cp) + key_count *
3219 sizeof(struct mgmt_ltk_info);
3220 if (expected_len != len) {
3221 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003222 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003223 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003224 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003225 }
3226
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003227 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003228
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003229 for (i = 0; i < key_count; i++) {
3230 struct mgmt_ltk_info *key = &cp->keys[i];
3231
Johan Hedberg3f706b72013-01-20 14:27:16 +02003232 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003233 return cmd_status(sk, hdev->id,
3234 MGMT_OP_LOAD_LONG_TERM_KEYS,
3235 MGMT_STATUS_INVALID_PARAMS);
3236 }
3237
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003238 hci_dev_lock(hdev);
3239
3240 hci_smp_ltks_clear(hdev);
3241
3242 for (i = 0; i < key_count; i++) {
3243 struct mgmt_ltk_info *key = &cp->keys[i];
3244 u8 type;
3245
3246 if (key->master)
3247 type = HCI_SMP_LTK;
3248 else
3249 type = HCI_SMP_LTK_SLAVE;
3250
Hemant Gupta4596fde2012-04-16 14:57:40 +05303251 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003252 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003253 type, 0, key->authenticated, key->val,
3254 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003255 }
3256
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003257 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3258 NULL, 0);
3259
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003260 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003261
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003262 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003263}
3264
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003265static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003266 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3267 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003268 bool var_len;
3269 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003270} mgmt_handlers[] = {
3271 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003272 { read_version, false, MGMT_READ_VERSION_SIZE },
3273 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3274 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3275 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3276 { set_powered, false, MGMT_SETTING_SIZE },
3277 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3278 { set_connectable, false, MGMT_SETTING_SIZE },
3279 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3280 { set_pairable, false, MGMT_SETTING_SIZE },
3281 { set_link_security, false, MGMT_SETTING_SIZE },
3282 { set_ssp, false, MGMT_SETTING_SIZE },
3283 { set_hs, false, MGMT_SETTING_SIZE },
3284 { set_le, false, MGMT_SETTING_SIZE },
3285 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3286 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3287 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3288 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3289 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3290 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3291 { disconnect, false, MGMT_DISCONNECT_SIZE },
3292 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3293 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3294 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3295 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3296 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3297 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3298 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3299 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3300 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3301 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3302 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3303 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3304 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3305 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3306 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3307 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3308 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3309 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3310 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003311 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003312};
3313
3314
Johan Hedberg03811012010-12-08 00:21:06 +02003315int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3316{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003317 void *buf;
3318 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003319 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003320 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003321 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003322 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003323 int err;
3324
3325 BT_DBG("got %zu bytes", msglen);
3326
3327 if (msglen < sizeof(*hdr))
3328 return -EINVAL;
3329
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003330 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003331 if (!buf)
3332 return -ENOMEM;
3333
3334 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3335 err = -EFAULT;
3336 goto done;
3337 }
3338
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003339 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003340 opcode = __le16_to_cpu(hdr->opcode);
3341 index = __le16_to_cpu(hdr->index);
3342 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003343
3344 if (len != msglen - sizeof(*hdr)) {
3345 err = -EINVAL;
3346 goto done;
3347 }
3348
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003349 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003350 hdev = hci_dev_get(index);
3351 if (!hdev) {
3352 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003353 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003354 goto done;
3355 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003356
3357 if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
3358 err = cmd_status(sk, index, opcode,
3359 MGMT_STATUS_INVALID_INDEX);
3360 goto done;
3361 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003362 }
3363
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003364 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003365 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003366 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003367 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003368 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003369 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003370 }
3371
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003372 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003373 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003374 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003375 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003376 goto done;
3377 }
3378
Johan Hedbergbe22b542012-03-01 22:24:41 +02003379 handler = &mgmt_handlers[opcode];
3380
3381 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003382 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003383 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003384 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003385 goto done;
3386 }
3387
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003388 if (hdev)
3389 mgmt_init_hdev(sk, hdev);
3390
3391 cp = buf + sizeof(*hdr);
3392
Johan Hedbergbe22b542012-03-01 22:24:41 +02003393 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003394 if (err < 0)
3395 goto done;
3396
Johan Hedberg03811012010-12-08 00:21:06 +02003397 err = msglen;
3398
3399done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003400 if (hdev)
3401 hci_dev_put(hdev);
3402
Johan Hedberg03811012010-12-08 00:21:06 +02003403 kfree(buf);
3404 return err;
3405}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003406
Johan Hedberg744cf192011-11-08 20:40:14 +02003407int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003408{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003409 if (!mgmt_valid_hdev(hdev))
3410 return -ENOTSUPP;
3411
Johan Hedberg744cf192011-11-08 20:40:14 +02003412 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003413}
3414
Johan Hedberg744cf192011-11-08 20:40:14 +02003415int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003416{
Johan Hedberg5f159032012-03-02 03:13:19 +02003417 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003418
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003419 if (!mgmt_valid_hdev(hdev))
3420 return -ENOTSUPP;
3421
Johan Hedberg744cf192011-11-08 20:40:14 +02003422 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003423
Johan Hedberg744cf192011-11-08 20:40:14 +02003424 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003425}
3426
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");