blob: a3329cbd3e4da52dc36987b40c9102262cea8e6b [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
Marcel Holtmann053262d2012-03-27 18:49:02 +020038#define MGMT_REVISION 1
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,
102};
103
Andre Guedes3fd24152012-02-03 17:48:01 -0300104/*
105 * These LE scan and inquiry parameters were chosen according to LE General
106 * Discovery Procedure specification.
107 */
108#define LE_SCAN_TYPE 0x01
109#define LE_SCAN_WIN 0x12
110#define LE_SCAN_INT 0x12
111#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300112#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300113
Andre Guedese8777522012-02-03 17:48:02 -0300114#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300115#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300116
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800117#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200118
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200119#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
120 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
121
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200122struct pending_cmd {
123 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200124 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200125 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100126 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300128 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129};
130
Johan Hedbergca69b792011-11-11 18:10:00 +0200131/* HCI to MGMT error code conversion table */
132static u8 mgmt_status_table[] = {
133 MGMT_STATUS_SUCCESS,
134 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
135 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
136 MGMT_STATUS_FAILED, /* Hardware Failure */
137 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
138 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
139 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
140 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
141 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
142 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
143 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
144 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
145 MGMT_STATUS_BUSY, /* Command Disallowed */
146 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
147 MGMT_STATUS_REJECTED, /* Rejected Security */
148 MGMT_STATUS_REJECTED, /* Rejected Personal */
149 MGMT_STATUS_TIMEOUT, /* Host Timeout */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
151 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
152 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
153 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
154 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
155 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
156 MGMT_STATUS_BUSY, /* Repeated Attempts */
157 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
158 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
159 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
160 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
161 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
162 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
163 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
164 MGMT_STATUS_FAILED, /* Unspecified Error */
165 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
166 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
167 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
168 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
169 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
170 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
171 MGMT_STATUS_FAILED, /* Unit Link Key Used */
172 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
173 MGMT_STATUS_TIMEOUT, /* Instant Passed */
174 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
175 MGMT_STATUS_FAILED, /* Transaction Collision */
176 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
177 MGMT_STATUS_REJECTED, /* QoS Rejected */
178 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
179 MGMT_STATUS_REJECTED, /* Insufficient Security */
180 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
181 MGMT_STATUS_BUSY, /* Role Switch Pending */
182 MGMT_STATUS_FAILED, /* Slot Violation */
183 MGMT_STATUS_FAILED, /* Role Switch Failed */
184 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
185 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
186 MGMT_STATUS_BUSY, /* Host Busy Pairing */
187 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
188 MGMT_STATUS_BUSY, /* Controller Busy */
189 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
190 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
191 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
192 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
193 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
194};
195
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300196bool mgmt_valid_hdev(struct hci_dev *hdev)
197{
198 return hdev->dev_type == HCI_BREDR;
199}
200
Johan Hedbergca69b792011-11-11 18:10:00 +0200201static u8 mgmt_status(u8 hci_status)
202{
203 if (hci_status < ARRAY_SIZE(mgmt_status_table))
204 return mgmt_status_table[hci_status];
205
206 return MGMT_STATUS_FAILED;
207}
208
Szymon Janc4e51eae2011-02-25 19:05:48 +0100209static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210{
211 struct sk_buff *skb;
212 struct mgmt_hdr *hdr;
213 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300214 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215
Szymon Janc34eb5252011-02-28 14:10:08 +0100216 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200217
Andre Guedes790eff42012-06-07 19:05:46 -0300218 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200219 if (!skb)
220 return -ENOMEM;
221
222 hdr = (void *) skb_put(skb, sizeof(*hdr));
223
224 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100225 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226 hdr->len = cpu_to_le16(sizeof(*ev));
227
228 ev = (void *) skb_put(skb, sizeof(*ev));
229 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200230 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300232 err = sock_queue_rcv_skb(sk, skb);
233 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234 kfree_skb(skb);
235
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300236 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200237}
238
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200239static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300240 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200241{
242 struct sk_buff *skb;
243 struct mgmt_hdr *hdr;
244 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300245 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200246
247 BT_DBG("sock %p", sk);
248
Andre Guedes790eff42012-06-07 19:05:46 -0300249 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200250 if (!skb)
251 return -ENOMEM;
252
253 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200254
Johan Hedberg02d98122010-12-13 21:07:04 +0200255 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100256 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200257 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200258
Johan Hedberga38528f2011-01-22 06:46:43 +0200259 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200260 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200261 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100262
263 if (rp)
264 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200265
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300266 err = sock_queue_rcv_skb(sk, skb);
267 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200268 kfree_skb(skb);
269
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100270 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200275{
276 struct mgmt_rp_read_version rp;
277
278 BT_DBG("sock %p", sk);
279
280 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200281 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200282
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200283 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300284 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200285}
286
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300287static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
288 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200289{
290 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
292 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200293 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200294 size_t rp_size;
295 int i, err;
296
297 BT_DBG("sock %p", sk);
298
299 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
300
301 rp = kmalloc(rp_size, GFP_KERNEL);
302 if (!rp)
303 return -ENOMEM;
304
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200305 rp->num_commands = __constant_cpu_to_le16(num_commands);
306 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200307
308 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
309 put_unaligned_le16(mgmt_commands[i], opcode);
310
311 for (i = 0; i < num_events; i++, opcode++)
312 put_unaligned_le16(mgmt_events[i], opcode);
313
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200314 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300315 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200316 kfree(rp);
317
318 return err;
319}
320
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300321static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
322 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200323{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200325 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200328 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329
330 BT_DBG("sock %p", sk);
331
332 read_lock(&hci_dev_list_lock);
333
334 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300335 list_for_each_entry(d, &hci_dev_list, list) {
336 if (!mgmt_valid_hdev(d))
337 continue;
338
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200339 count++;
340 }
341
Johan Hedberga38528f2011-01-22 06:46:43 +0200342 rp_len = sizeof(*rp) + (2 * count);
343 rp = kmalloc(rp_len, GFP_ATOMIC);
344 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100345 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200346 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100347 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200349 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350
351 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200352 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200353 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200354 continue;
355
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300356 if (!mgmt_valid_hdev(d))
357 continue;
358
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200359 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360 BT_DBG("Added hci%u", d->id);
361 }
362
363 read_unlock(&hci_dev_list_lock);
364
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200365 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300366 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200367
Johan Hedberga38528f2011-01-22 06:46:43 +0200368 kfree(rp);
369
370 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200371}
372
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200374{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200376
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200377 settings |= MGMT_SETTING_POWERED;
378 settings |= MGMT_SETTING_CONNECTABLE;
379 settings |= MGMT_SETTING_FAST_CONNECTABLE;
380 settings |= MGMT_SETTING_DISCOVERABLE;
381 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200382
Andre Guedes9a1a1992012-07-24 15:03:48 -0300383 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200384 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200385
Andre Guedesed3fa312012-07-24 15:03:46 -0300386 if (lmp_bredr_capable(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387 settings |= MGMT_SETTING_BREDR;
388 settings |= MGMT_SETTING_LINK_SECURITY;
389 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200390
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100391 if (enable_hs)
392 settings |= MGMT_SETTING_HS;
393
Andre Guedesc383ddc2012-07-24 15:03:47 -0300394 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200395 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200396
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397 return settings;
398}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200399
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400static u32 get_current_settings(struct hci_dev *hdev)
401{
402 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200403
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200404 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100405 settings |= MGMT_SETTING_POWERED;
406
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200407 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_CONNECTABLE;
409
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200410 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_DISCOVERABLE;
412
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200413 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_PAIRABLE;
415
Andre Guedesed3fa312012-07-24 15:03:46 -0300416 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_BREDR;
418
Johan Hedberg06199cf2012-02-22 16:37:11 +0200419 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg47990ea2012-02-22 11:58:37 +0200422 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200424
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200425 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200427
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200428 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
429 settings |= MGMT_SETTING_HS;
430
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200431 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200432}
433
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300434#define PNP_INFO_SVCLASS_ID 0x1200
435
436static u8 bluetooth_base_uuid[] = {
437 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
438 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
439};
440
441static u16 get_uuid16(u8 *uuid128)
442{
443 u32 val;
444 int i;
445
446 for (i = 0; i < 12; i++) {
447 if (bluetooth_base_uuid[i] != uuid128[i])
448 return 0;
449 }
450
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200451 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300452 if (val > 0xffff)
453 return 0;
454
455 return (u16) val;
456}
457
458static void create_eir(struct hci_dev *hdev, u8 *data)
459{
460 u8 *ptr = data;
461 u16 eir_len = 0;
462 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
463 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200464 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300465 size_t name_len;
466
467 name_len = strlen(hdev->dev_name);
468
469 if (name_len > 0) {
470 /* EIR Data type */
471 if (name_len > 48) {
472 name_len = 48;
473 ptr[1] = EIR_NAME_SHORT;
474 } else
475 ptr[1] = EIR_NAME_COMPLETE;
476
477 /* EIR Data length */
478 ptr[0] = name_len + 1;
479
480 memcpy(ptr + 2, hdev->dev_name, name_len);
481
482 eir_len += (name_len + 2);
483 ptr += (name_len + 2);
484 }
485
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700486 if (hdev->inq_tx_power) {
487 ptr[0] = 2;
488 ptr[1] = EIR_TX_POWER;
489 ptr[2] = (u8) hdev->inq_tx_power;
490
491 eir_len += 3;
492 ptr += 3;
493 }
494
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700495 if (hdev->devid_source > 0) {
496 ptr[0] = 9;
497 ptr[1] = EIR_DEVICE_ID;
498
499 put_unaligned_le16(hdev->devid_source, ptr + 2);
500 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
501 put_unaligned_le16(hdev->devid_product, ptr + 6);
502 put_unaligned_le16(hdev->devid_version, ptr + 8);
503
504 eir_len += 10;
505 ptr += 10;
506 }
507
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300508 memset(uuid16_list, 0, sizeof(uuid16_list));
509
510 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200511 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300512 u16 uuid16;
513
514 uuid16 = get_uuid16(uuid->uuid);
515 if (uuid16 == 0)
516 return;
517
518 if (uuid16 < 0x1100)
519 continue;
520
521 if (uuid16 == PNP_INFO_SVCLASS_ID)
522 continue;
523
524 /* Stop if not enough space to put next UUID */
525 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
526 truncated = 1;
527 break;
528 }
529
530 /* Check for duplicates */
531 for (i = 0; uuid16_list[i] != 0; i++)
532 if (uuid16_list[i] == uuid16)
533 break;
534
535 if (uuid16_list[i] == 0) {
536 uuid16_list[i] = uuid16;
537 eir_len += sizeof(u16);
538 }
539 }
540
541 if (uuid16_list[0] != 0) {
542 u8 *length = ptr;
543
544 /* EIR Data type */
545 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
546
547 ptr += 2;
548 eir_len += 2;
549
550 for (i = 0; uuid16_list[i] != 0; i++) {
551 *ptr++ = (uuid16_list[i] & 0x00ff);
552 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
553 }
554
555 /* EIR Data length */
556 *length = (i * sizeof(u16)) + 1;
557 }
558}
559
560static int update_eir(struct hci_dev *hdev)
561{
562 struct hci_cp_write_eir cp;
563
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200564 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200565 return 0;
566
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300567 if (!(hdev->features[6] & LMP_EXT_INQ))
568 return 0;
569
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200570 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300571 return 0;
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300574 return 0;
575
576 memset(&cp, 0, sizeof(cp));
577
578 create_eir(hdev, cp.data);
579
580 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
581 return 0;
582
583 memcpy(hdev->eir, cp.data, sizeof(cp.data));
584
585 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
586}
587
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200588static u8 get_service_classes(struct hci_dev *hdev)
589{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300590 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200591 u8 val = 0;
592
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300593 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200594 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595
596 return val;
597}
598
599static int update_class(struct hci_dev *hdev)
600{
601 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200602 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200603
604 BT_DBG("%s", hdev->name);
605
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200606 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200607 return 0;
608
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200609 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200610 return 0;
611
612 cod[0] = hdev->minor_class;
613 cod[1] = hdev->major_class;
614 cod[2] = get_service_classes(hdev);
615
616 if (memcmp(cod, hdev->dev_class, 3) == 0)
617 return 0;
618
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200619 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
620 if (err == 0)
621 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
622
623 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624}
625
Johan Hedberg7d785252011-12-15 00:47:39 +0200626static void service_cache_off(struct work_struct *work)
627{
628 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300629 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200630
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200631 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200632 return;
633
634 hci_dev_lock(hdev);
635
636 update_eir(hdev);
637 update_class(hdev);
638
639 hci_dev_unlock(hdev);
640}
641
Johan Hedberg6a919082012-02-28 06:17:26 +0200642static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200643{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200644 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200645 return;
646
Johan Hedberg4f87da82012-03-02 19:55:56 +0200647 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200648
Johan Hedberg4f87da82012-03-02 19:55:56 +0200649 /* Non-mgmt controlled devices get this bit set
650 * implicitly so that pairing works for them, however
651 * for mgmt we require user-space to explicitly enable
652 * it
653 */
654 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200655}
656
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200657static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300658 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200659{
660 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200661
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200662 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200663
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300664 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200665
Johan Hedberg03811012010-12-08 00:21:06 +0200666 memset(&rp, 0, sizeof(rp));
667
Johan Hedberg03811012010-12-08 00:21:06 +0200668 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669
670 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200671 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672
673 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
674 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
675
676 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200677
678 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200679 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200680
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300681 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200682
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200683 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300684 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200685}
686
687static void mgmt_pending_free(struct pending_cmd *cmd)
688{
689 sock_put(cmd->sk);
690 kfree(cmd->param);
691 kfree(cmd);
692}
693
694static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300695 struct hci_dev *hdev, void *data,
696 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200697{
698 struct pending_cmd *cmd;
699
Andre Guedes12b94562012-06-07 19:05:45 -0300700 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200701 if (!cmd)
702 return NULL;
703
704 cmd->opcode = opcode;
705 cmd->index = hdev->id;
706
Andre Guedes12b94562012-06-07 19:05:45 -0300707 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200708 if (!cmd->param) {
709 kfree(cmd);
710 return NULL;
711 }
712
713 if (data)
714 memcpy(cmd->param, data, len);
715
716 cmd->sk = sk;
717 sock_hold(sk);
718
719 list_add(&cmd->list, &hdev->mgmt_pending);
720
721 return cmd;
722}
723
724static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300725 void (*cb)(struct pending_cmd *cmd,
726 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300727 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200728{
729 struct list_head *p, *n;
730
731 list_for_each_safe(p, n, &hdev->mgmt_pending) {
732 struct pending_cmd *cmd;
733
734 cmd = list_entry(p, struct pending_cmd, list);
735
736 if (opcode > 0 && cmd->opcode != opcode)
737 continue;
738
739 cb(cmd, data);
740 }
741}
742
743static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
744{
745 struct pending_cmd *cmd;
746
747 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
748 if (cmd->opcode == opcode)
749 return cmd;
750 }
751
752 return NULL;
753}
754
755static void mgmt_pending_remove(struct pending_cmd *cmd)
756{
757 list_del(&cmd->list);
758 mgmt_pending_free(cmd);
759}
760
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200761static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200762{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200763 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200764
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200765 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300766 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200767}
768
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200769static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300770 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200771{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300772 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200773 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200774 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200775
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200776 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200777
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300778 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200779
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100780 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
781 cancel_delayed_work(&hdev->power_off);
782
783 if (cp->val) {
784 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
785 mgmt_powered(hdev, 1);
786 goto failed;
787 }
788 }
789
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200790 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200791 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200792 goto failed;
793 }
794
795 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200796 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300797 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200798 goto failed;
799 }
800
801 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
802 if (!cmd) {
803 err = -ENOMEM;
804 goto failed;
805 }
806
807 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200808 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200809 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200810 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200811
812 err = 0;
813
814failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300815 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200816 return err;
817}
818
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300819static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
820 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200821{
822 struct sk_buff *skb;
823 struct mgmt_hdr *hdr;
824
Andre Guedes790eff42012-06-07 19:05:46 -0300825 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200826 if (!skb)
827 return -ENOMEM;
828
829 hdr = (void *) skb_put(skb, sizeof(*hdr));
830 hdr->opcode = cpu_to_le16(event);
831 if (hdev)
832 hdr->index = cpu_to_le16(hdev->id);
833 else
834 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
835 hdr->len = cpu_to_le16(data_len);
836
837 if (data)
838 memcpy(skb_put(skb, data_len), data, data_len);
839
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100840 /* Time stamp */
841 __net_timestamp(skb);
842
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200843 hci_send_to_control(skb, skip_sk);
844 kfree_skb(skb);
845
846 return 0;
847}
848
849static int new_settings(struct hci_dev *hdev, struct sock *skip)
850{
851 __le32 ev;
852
853 ev = cpu_to_le32(get_current_settings(hdev));
854
855 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
856}
857
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200858static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300859 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200860{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300861 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200862 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200863 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200864 u8 scan;
865 int err;
866
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200867 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200868
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700869 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100870 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200871 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300872 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200873
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300874 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200875
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200876 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200877 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300878 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200879 goto failed;
880 }
881
882 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300883 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200884 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300885 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200886 goto failed;
887 }
888
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200889 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200890 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300891 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200892 goto failed;
893 }
894
895 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200896 bool changed = false;
897
898 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
899 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
900 changed = true;
901 }
902
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200903 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200904 if (err < 0)
905 goto failed;
906
907 if (changed)
908 err = new_settings(hdev, sk);
909
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200910 goto failed;
911 }
912
913 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100914 if (hdev->discov_timeout > 0) {
915 cancel_delayed_work(&hdev->discov_off);
916 hdev->discov_timeout = 0;
917 }
918
919 if (cp->val && timeout > 0) {
920 hdev->discov_timeout = timeout;
921 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
922 msecs_to_jiffies(hdev->discov_timeout * 1000));
923 }
924
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200925 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200926 goto failed;
927 }
928
929 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
930 if (!cmd) {
931 err = -ENOMEM;
932 goto failed;
933 }
934
935 scan = SCAN_PAGE;
936
937 if (cp->val)
938 scan |= SCAN_INQUIRY;
939 else
940 cancel_delayed_work(&hdev->discov_off);
941
942 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
943 if (err < 0)
944 mgmt_pending_remove(cmd);
945
Johan Hedberg03811012010-12-08 00:21:06 +0200946 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200947 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200948
949failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300950 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200951 return err;
952}
953
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200954static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300955 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200956{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300957 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200958 struct pending_cmd *cmd;
959 u8 scan;
960 int err;
961
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200962 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200963
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300964 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200965
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200966 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200967 bool changed = false;
968
969 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
970 changed = true;
971
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200972 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200973 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200974 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
976 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
977 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200978
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200980 if (err < 0)
981 goto failed;
982
983 if (changed)
984 err = new_settings(hdev, sk);
985
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200986 goto failed;
987 }
988
989 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300990 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200991 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300992 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 goto failed;
994 }
995
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200996 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200997 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200998 goto failed;
999 }
1000
1001 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1002 if (!cmd) {
1003 err = -ENOMEM;
1004 goto failed;
1005 }
1006
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001007 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001008 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001009 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001010 scan = 0;
1011
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001012 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001013 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001014 cancel_delayed_work(&hdev->discov_off);
1015 }
1016
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1018 if (err < 0)
1019 mgmt_pending_remove(cmd);
1020
1021failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001022 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023 return err;
1024}
1025
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001026static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001027 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001028{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001029 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001030 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001032 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001034 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001035
1036 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001037 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001038 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001039 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001041 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042 if (err < 0)
1043 goto failed;
1044
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001045 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046
1047failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001048 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001049 return err;
1050}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001051
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001052static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1053 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001054{
1055 struct mgmt_mode *cp = data;
1056 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001057 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001058 int err;
1059
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001060 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001061
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001062 hci_dev_lock(hdev);
1063
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001064 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001065 bool changed = false;
1066
1067 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001068 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001069 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1070 changed = true;
1071 }
1072
1073 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1074 if (err < 0)
1075 goto failed;
1076
1077 if (changed)
1078 err = new_settings(hdev, sk);
1079
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001080 goto failed;
1081 }
1082
1083 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001084 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001085 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001086 goto failed;
1087 }
1088
1089 val = !!cp->val;
1090
1091 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1092 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1093 goto failed;
1094 }
1095
1096 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1097 if (!cmd) {
1098 err = -ENOMEM;
1099 goto failed;
1100 }
1101
1102 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1103 if (err < 0) {
1104 mgmt_pending_remove(cmd);
1105 goto failed;
1106 }
1107
1108failed:
1109 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001110 return err;
1111}
1112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001113static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001114{
1115 struct mgmt_mode *cp = data;
1116 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001117 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001118 int err;
1119
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001120 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001121
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001122 hci_dev_lock(hdev);
1123
Andre Guedes9a1a1992012-07-24 15:03:48 -03001124 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001125 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001126 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001127 goto failed;
1128 }
1129
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001130 val = !!cp->val;
1131
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001132 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001133 bool changed = false;
1134
1135 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1136 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1137 changed = true;
1138 }
1139
1140 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1141 if (err < 0)
1142 goto failed;
1143
1144 if (changed)
1145 err = new_settings(hdev, sk);
1146
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001147 goto failed;
1148 }
1149
1150 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001151 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1152 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001153 goto failed;
1154 }
1155
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001156 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1157 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1158 goto failed;
1159 }
1160
1161 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1162 if (!cmd) {
1163 err = -ENOMEM;
1164 goto failed;
1165 }
1166
1167 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1168 if (err < 0) {
1169 mgmt_pending_remove(cmd);
1170 goto failed;
1171 }
1172
1173failed:
1174 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001175 return err;
1176}
1177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001179{
1180 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001181
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001182 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001184 if (!enable_hs)
1185 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001186 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001187
1188 if (cp->val)
1189 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1190 else
1191 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001193 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001194}
1195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001196static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001197{
1198 struct mgmt_mode *cp = data;
1199 struct hci_cp_write_le_host_supported hci_cp;
1200 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001201 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001202 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001204 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001205
Johan Hedberg1de028c2012-02-29 19:55:35 -08001206 hci_dev_lock(hdev);
1207
Andre Guedesc383ddc2012-07-24 15:03:47 -03001208 if (!lmp_le_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001209 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001210 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001211 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001212 }
1213
1214 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001215 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001216
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001217 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001218 bool changed = false;
1219
1220 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1221 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1222 changed = true;
1223 }
1224
1225 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1226 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001227 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001228
1229 if (changed)
1230 err = new_settings(hdev, sk);
1231
Johan Hedberg1de028c2012-02-29 19:55:35 -08001232 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001233 }
1234
1235 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001236 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001237 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001238 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001239 }
1240
1241 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1242 if (!cmd) {
1243 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001244 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001245 }
1246
1247 memset(&hci_cp, 0, sizeof(hci_cp));
1248
1249 if (val) {
1250 hci_cp.le = val;
1251 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1252 }
1253
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001254 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1255 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301256 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001257 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001258
Johan Hedberg1de028c2012-02-29 19:55:35 -08001259unlock:
1260 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001261 return err;
1262}
1263
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001264static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001265{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001266 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001267 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001268 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001269 int err;
1270
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001271 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001273 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001274
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001275 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001276 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001277 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001278 goto failed;
1279 }
1280
Andre Guedes92c4c202012-06-07 19:05:44 -03001281 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001282 if (!uuid) {
1283 err = -ENOMEM;
1284 goto failed;
1285 }
1286
1287 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001288 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001289
1290 list_add(&uuid->list, &hdev->uuids);
1291
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001292 err = update_class(hdev);
1293 if (err < 0)
1294 goto failed;
1295
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001296 err = update_eir(hdev);
1297 if (err < 0)
1298 goto failed;
1299
Johan Hedberg90e70452012-02-23 23:09:40 +02001300 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001301 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001302 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001303 goto failed;
1304 }
1305
1306 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301307 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001308 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001309
1310failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001311 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 return err;
1313}
1314
Johan Hedberg24b78d02012-02-23 23:24:30 +02001315static bool enable_service_cache(struct hci_dev *hdev)
1316{
1317 if (!hdev_is_powered(hdev))
1318 return false;
1319
1320 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001321 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001322 return true;
1323 }
1324
1325 return false;
1326}
1327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001328static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001329 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001331 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001332 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001333 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 int err, found;
1336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001337 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001339 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001340
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001341 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001344 goto unlock;
1345 }
1346
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1348 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001349
Johan Hedberg24b78d02012-02-23 23:24:30 +02001350 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001351 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001352 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001353 goto unlock;
1354 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001355
Johan Hedberg9246a862012-02-23 21:33:16 +02001356 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001357 }
1358
1359 found = 0;
1360
1361 list_for_each_safe(p, n, &hdev->uuids) {
1362 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1363
1364 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1365 continue;
1366
1367 list_del(&match->list);
1368 found++;
1369 }
1370
1371 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001372 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001373 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001374 goto unlock;
1375 }
1376
Johan Hedberg9246a862012-02-23 21:33:16 +02001377update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001378 err = update_class(hdev);
1379 if (err < 0)
1380 goto unlock;
1381
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001382 err = update_eir(hdev);
1383 if (err < 0)
1384 goto unlock;
1385
Johan Hedberg90e70452012-02-23 23:09:40 +02001386 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001387 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001388 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001389 goto unlock;
1390 }
1391
1392 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301393 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001394 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001395
1396unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001397 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001398 return err;
1399}
1400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001401static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001402 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001403{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001404 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001405 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001406 int err;
1407
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001408 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001409
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001410 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001411
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001412 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001413 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001414 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001415 goto unlock;
1416 }
1417
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001418 hdev->major_class = cp->major;
1419 hdev->minor_class = cp->minor;
1420
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001421 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001422 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001423 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001424 goto unlock;
1425 }
1426
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001427 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001428 hci_dev_unlock(hdev);
1429 cancel_delayed_work_sync(&hdev->service_cache);
1430 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001431 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001432 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001433
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001434 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001435 if (err < 0)
1436 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001437
Johan Hedberg90e70452012-02-23 23:09:40 +02001438 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001439 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001440 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001441 goto unlock;
1442 }
1443
1444 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301445 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001446 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001447
Johan Hedbergb5235a62012-02-21 14:32:24 +02001448unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001449 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001450 return err;
1451}
1452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001453static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001454 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001455{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001456 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001457 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001458 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001459
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001460 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001461
Johan Hedberg86742e12011-11-07 23:13:38 +02001462 expected_len = sizeof(*cp) + key_count *
1463 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001464 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001465 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001466 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001467 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001468 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469 }
1470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001471 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001472 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001474 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001475
1476 hci_link_keys_clear(hdev);
1477
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001478 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001479
1480 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001481 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001482 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001483 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001484
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001485 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001486 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001487
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001488 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001489 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001490 }
1491
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001492 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001493
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001494 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001495
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001496 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001497}
1498
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001499static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001500 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001501{
1502 struct mgmt_ev_device_unpaired ev;
1503
1504 bacpy(&ev.addr.bdaddr, bdaddr);
1505 ev.addr.type = addr_type;
1506
1507 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001508 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001509}
1510
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001511static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001512 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001513{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001514 struct mgmt_cp_unpair_device *cp = data;
1515 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001516 struct hci_cp_disconnect dc;
1517 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001518 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001519 int err;
1520
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001521 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001522
Johan Hedberga8a1d192011-11-10 15:54:38 +02001523 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001524 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1525 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001526
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001527 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001528 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001529 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001530 goto unlock;
1531 }
1532
Andre Guedes591f47f2012-04-24 21:02:49 -03001533 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001534 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1535 else
1536 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001537
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001538 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001539 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001540 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001541 goto unlock;
1542 }
1543
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001544 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001545 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001546 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001547 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001548 else
1549 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001550 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001551 } else {
1552 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001553 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001554
Johan Hedberga8a1d192011-11-10 15:54:38 +02001555 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001556 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001557 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001558 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001559 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001560 }
1561
Johan Hedberg124f6e32012-02-09 13:50:12 +02001562 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001563 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001564 if (!cmd) {
1565 err = -ENOMEM;
1566 goto unlock;
1567 }
1568
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001569 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001570 dc.reason = 0x13; /* Remote User Terminated Connection */
1571 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1572 if (err < 0)
1573 mgmt_pending_remove(cmd);
1574
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001575unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001576 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001577 return err;
1578}
1579
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001580static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001581 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001582{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001583 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001584 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001585 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001587 int err;
1588
1589 BT_DBG("");
1590
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001591 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001592
1593 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001594 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001595 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001596 goto failed;
1597 }
1598
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001599 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001600 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001601 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001602 goto failed;
1603 }
1604
Andre Guedes591f47f2012-04-24 21:02:49 -03001605 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001606 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1607 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001608 else
1609 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001610
Vishal Agarwalf9607272012-06-13 05:32:43 +05301611 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001612 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001613 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001614 goto failed;
1615 }
1616
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001617 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001618 if (!cmd) {
1619 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001620 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001621 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001622
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001623 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001624 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001625
1626 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1627 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001628 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001629
1630failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001631 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001632 return err;
1633}
1634
Andre Guedes57c14772012-04-24 21:02:50 -03001635static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001636{
1637 switch (link_type) {
1638 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001639 switch (addr_type) {
1640 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001641 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001642
Johan Hedberg48264f02011-11-09 13:58:58 +02001643 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001644 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001645 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001646 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001647
Johan Hedberg4c659c32011-11-07 23:13:39 +02001648 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001649 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001650 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001651 }
1652}
1653
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001654static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1655 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001656{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001657 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001658 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001659 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001660 int err;
1661 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001662
1663 BT_DBG("");
1664
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001665 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001666
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001667 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001668 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001669 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001670 goto unlock;
1671 }
1672
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001673 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001674 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1675 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001676 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001677 }
1678
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001679 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001680 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001681 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001682 err = -ENOMEM;
1683 goto unlock;
1684 }
1685
Johan Hedberg2784eb42011-01-21 13:56:35 +02001686 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001687 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001688 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1689 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001690 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001691 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001692 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001693 continue;
1694 i++;
1695 }
1696
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001697 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001698
Johan Hedberg4c659c32011-11-07 23:13:39 +02001699 /* Recalculate length in case of filtered SCO connections, etc */
1700 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001702 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001703 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001704
Johan Hedberga38528f2011-01-22 06:46:43 +02001705 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001706
1707unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001708 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001709 return err;
1710}
1711
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001712static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001713 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001714{
1715 struct pending_cmd *cmd;
1716 int err;
1717
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001718 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001719 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001720 if (!cmd)
1721 return -ENOMEM;
1722
Johan Hedbergd8457692012-02-17 14:24:57 +02001723 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001724 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001725 if (err < 0)
1726 mgmt_pending_remove(cmd);
1727
1728 return err;
1729}
1730
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001731static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001732 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001733{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001734 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001735 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001736 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001737 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001738 int err;
1739
1740 BT_DBG("");
1741
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001742 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001743
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001744 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001745 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001746 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001747 goto failed;
1748 }
1749
Johan Hedbergd8457692012-02-17 14:24:57 +02001750 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001751 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001752 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001753 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001754 goto failed;
1755 }
1756
1757 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001758 struct mgmt_cp_pin_code_neg_reply ncp;
1759
1760 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001761
1762 BT_ERR("PIN code is not 16 bytes long");
1763
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001764 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001765 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001766 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001767 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001768
1769 goto failed;
1770 }
1771
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001772 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001773 if (!cmd) {
1774 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001775 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001776 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001777
Johan Hedbergd8457692012-02-17 14:24:57 +02001778 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001779 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001780 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001781
1782 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1783 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001784 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785
1786failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001787 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001788 return err;
1789}
1790
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001791static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1792 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001793{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001794 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001795
1796 BT_DBG("");
1797
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001798 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001799
1800 hdev->io_capability = cp->io_capability;
1801
1802 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001803 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001804
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001805 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001806
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001807 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1808 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001809}
1810
Gustavo Padovan6039aa732012-05-23 04:04:18 -03001811static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001812{
1813 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001814 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001815
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001816 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001817 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1818 continue;
1819
Johan Hedberge9a416b2011-02-19 12:05:56 -03001820 if (cmd->user_data != conn)
1821 continue;
1822
1823 return cmd;
1824 }
1825
1826 return NULL;
1827}
1828
1829static void pairing_complete(struct pending_cmd *cmd, u8 status)
1830{
1831 struct mgmt_rp_pair_device rp;
1832 struct hci_conn *conn = cmd->user_data;
1833
Johan Hedbergba4e5642011-11-11 00:07:34 +02001834 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001835 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001836
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001837 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001838 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001839
1840 /* So we don't get further callbacks for this connection */
1841 conn->connect_cfm_cb = NULL;
1842 conn->security_cfm_cb = NULL;
1843 conn->disconn_cfm_cb = NULL;
1844
1845 hci_conn_put(conn);
1846
Johan Hedberga664b5b2011-02-19 12:06:02 -03001847 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001848}
1849
1850static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1851{
1852 struct pending_cmd *cmd;
1853
1854 BT_DBG("status %u", status);
1855
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001856 cmd = find_pairing(conn);
1857 if (!cmd)
1858 BT_DBG("Unable to find a pending command");
1859 else
Johan Hedberge2113262012-02-18 15:20:03 +02001860 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001861}
1862
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301863static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1864{
1865 struct pending_cmd *cmd;
1866
1867 BT_DBG("status %u", status);
1868
1869 if (!status)
1870 return;
1871
1872 cmd = find_pairing(conn);
1873 if (!cmd)
1874 BT_DBG("Unable to find a pending command");
1875 else
1876 pairing_complete(cmd, mgmt_status(status));
1877}
1878
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001879static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001880 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001881{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001882 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001883 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001884 struct pending_cmd *cmd;
1885 u8 sec_level, auth_type;
1886 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887 int err;
1888
1889 BT_DBG("");
1890
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001891 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001892
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001893 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001894 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001895 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001896 goto unlock;
1897 }
1898
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001899 sec_level = BT_SECURITY_MEDIUM;
1900 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001901 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001902 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001903 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001904
Andre Guedes591f47f2012-04-24 21:02:49 -03001905 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001906 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1907 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001908 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001909 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1910 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001911
Johan Hedberg1425acb2011-11-11 00:07:35 +02001912 memset(&rp, 0, sizeof(rp));
1913 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1914 rp.addr.type = cp->addr.type;
1915
Ville Tervo30e76272011-02-22 16:10:53 -03001916 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001917 int status;
1918
1919 if (PTR_ERR(conn) == -EBUSY)
1920 status = MGMT_STATUS_BUSY;
1921 else
1922 status = MGMT_STATUS_CONNECT_FAILED;
1923
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001924 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001925 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001926 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001927 goto unlock;
1928 }
1929
1930 if (conn->connect_cfm_cb) {
1931 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001932 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001933 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001934 goto unlock;
1935 }
1936
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001937 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001938 if (!cmd) {
1939 err = -ENOMEM;
1940 hci_conn_put(conn);
1941 goto unlock;
1942 }
1943
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001944 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001945 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001946 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301947 else
1948 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001949
Johan Hedberge9a416b2011-02-19 12:05:56 -03001950 conn->security_cfm_cb = pairing_complete_cb;
1951 conn->disconn_cfm_cb = pairing_complete_cb;
1952 conn->io_capability = cp->io_cap;
1953 cmd->user_data = conn;
1954
1955 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001956 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03001957 pairing_complete(cmd, 0);
1958
1959 err = 0;
1960
1961unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001962 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001963 return err;
1964}
1965
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001966static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1967 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001968{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001969 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001970 struct pending_cmd *cmd;
1971 struct hci_conn *conn;
1972 int err;
1973
1974 BT_DBG("");
1975
Johan Hedberg28424702012-02-02 04:02:29 +02001976 hci_dev_lock(hdev);
1977
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001978 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001979 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001980 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001981 goto unlock;
1982 }
1983
Johan Hedberg28424702012-02-02 04:02:29 +02001984 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1985 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001986 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001987 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001988 goto unlock;
1989 }
1990
1991 conn = cmd->user_data;
1992
1993 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001994 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001995 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001996 goto unlock;
1997 }
1998
1999 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2000
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002001 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002002 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002003unlock:
2004 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002005 return err;
2006}
2007
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002008static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002009 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2010 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002011{
Johan Hedberga5c29682011-02-19 12:05:57 -03002012 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002013 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002014 int err;
2015
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002016 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002017
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002018 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002019 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002020 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002021 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002022 }
2023
Andre Guedes591f47f2012-04-24 21:02:49 -03002024 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002025 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2026 else
Brian Gix47c15e22011-11-16 13:53:14 -08002027 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002028
Johan Hedberg272d90d2012-02-09 15:26:12 +02002029 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002030 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002031 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002032 goto done;
2033 }
2034
Andre Guedes591f47f2012-04-24 21:02:49 -03002035 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002036 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002037 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002038
Brian Gix5fe57d92011-12-21 16:12:13 -08002039 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002040 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002041 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002042 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002043 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002044 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002045
Brian Gix47c15e22011-11-16 13:53:14 -08002046 goto done;
2047 }
2048
Brian Gix0df4c182011-11-16 13:53:13 -08002049 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002050 if (!cmd) {
2051 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002052 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002053 }
2054
Brian Gix0df4c182011-11-16 13:53:13 -08002055 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002056 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2057 struct hci_cp_user_passkey_reply cp;
2058
2059 bacpy(&cp.bdaddr, bdaddr);
2060 cp.passkey = passkey;
2061 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2062 } else
2063 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2064
Johan Hedberga664b5b2011-02-19 12:06:02 -03002065 if (err < 0)
2066 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002067
Brian Gix0df4c182011-11-16 13:53:13 -08002068done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002069 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002070 return err;
2071}
2072
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302073static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2074 void *data, u16 len)
2075{
2076 struct mgmt_cp_pin_code_neg_reply *cp = data;
2077
2078 BT_DBG("");
2079
2080 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2081 MGMT_OP_PIN_CODE_NEG_REPLY,
2082 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2083}
2084
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002085static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2086 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002087{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002088 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002089
2090 BT_DBG("");
2091
2092 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002093 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002094 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002096 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002097 MGMT_OP_USER_CONFIRM_REPLY,
2098 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002099}
2100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002101static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002102 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002103{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002104 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002105
2106 BT_DBG("");
2107
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002108 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002109 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2110 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002111}
2112
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002113static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2114 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002115{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002116 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002117
2118 BT_DBG("");
2119
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002120 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002121 MGMT_OP_USER_PASSKEY_REPLY,
2122 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002123}
2124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002125static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002126 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002127{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002128 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002129
2130 BT_DBG("");
2131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002132 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002133 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2134 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002135}
2136
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002137static int update_name(struct hci_dev *hdev, const char *name)
2138{
2139 struct hci_cp_write_local_name cp;
2140
2141 memcpy(cp.name, name, sizeof(cp.name));
2142
2143 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2144}
2145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002146static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002147 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002148{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002149 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002150 struct pending_cmd *cmd;
2151 int err;
2152
2153 BT_DBG("");
2154
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002155 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002156
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002157 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002158
Johan Hedbergb5235a62012-02-21 14:32:24 +02002159 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002160 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002161
2162 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002163 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002164 if (err < 0)
2165 goto failed;
2166
2167 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002168 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002169
Johan Hedbergb5235a62012-02-21 14:32:24 +02002170 goto failed;
2171 }
2172
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002173 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002174 if (!cmd) {
2175 err = -ENOMEM;
2176 goto failed;
2177 }
2178
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002179 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002180 if (err < 0)
2181 mgmt_pending_remove(cmd);
2182
2183failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002184 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002185 return err;
2186}
2187
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002188static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002189 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002190{
Szymon Jancc35938b2011-03-22 13:12:21 +01002191 struct pending_cmd *cmd;
2192 int err;
2193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002195
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002196 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002197
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002198 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002199 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002200 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002201 goto unlock;
2202 }
2203
Andre Guedes9a1a1992012-07-24 15:03:48 -03002204 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002205 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002206 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002207 goto unlock;
2208 }
2209
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002210 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002211 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002212 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002213 goto unlock;
2214 }
2215
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002216 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002217 if (!cmd) {
2218 err = -ENOMEM;
2219 goto unlock;
2220 }
2221
2222 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2223 if (err < 0)
2224 mgmt_pending_remove(cmd);
2225
2226unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002227 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002228 return err;
2229}
2230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002232 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002233{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002234 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002235 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002236 int err;
2237
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002238 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002239
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002241
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002242 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002243 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002244 MGMT_STATUS_NOT_POWERED, &cp->addr,
2245 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002246 goto unlock;
2247 }
2248
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002249 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002250 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002251 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002252 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002253 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002254 status = 0;
2255
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002256 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002257 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002258
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002259unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002260 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261 return err;
2262}
2263
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002264static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002265 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002266{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002267 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002268 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002269 int err;
2270
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002271 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002272
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002273 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002274
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002275 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002276 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002277 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2278 MGMT_STATUS_NOT_POWERED, &cp->addr,
2279 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002280 goto unlock;
2281 }
2282
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002283 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002284 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002285 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002286 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002287 status = 0;
2288
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002289 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002290 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002291
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002292unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002293 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002294 return err;
2295}
2296
Andre Guedes5e0452c2012-02-17 20:39:38 -03002297int mgmt_interleaved_discovery(struct hci_dev *hdev)
2298{
2299 int err;
2300
2301 BT_DBG("%s", hdev->name);
2302
2303 hci_dev_lock(hdev);
2304
2305 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2306 if (err < 0)
2307 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2308
2309 hci_dev_unlock(hdev);
2310
2311 return err;
2312}
2313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002314static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002315 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002316{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002317 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002318 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002319 int err;
2320
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002322
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002323 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002324
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002325 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002326 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002327 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002328 goto failed;
2329 }
2330
Andre Guedes642be6c2012-03-21 00:03:37 -03002331 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2332 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2333 MGMT_STATUS_BUSY);
2334 goto failed;
2335 }
2336
Johan Hedbergff9ef572012-01-04 14:23:45 +02002337 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002338 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002339 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002340 goto failed;
2341 }
2342
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002343 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002344 if (!cmd) {
2345 err = -ENOMEM;
2346 goto failed;
2347 }
2348
Andre Guedes4aab14e2012-02-17 20:39:36 -03002349 hdev->discovery.type = cp->type;
2350
2351 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002352 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002353 if (lmp_bredr_capable(hdev))
2354 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2355 else
2356 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002357 break;
2358
2359 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002360 if (lmp_host_le_capable(hdev))
2361 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002362 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002363 else
2364 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002365 break;
2366
Andre Guedes5e0452c2012-02-17 20:39:38 -03002367 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002368 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2369 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002370 LE_SCAN_WIN,
2371 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002372 else
2373 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002374 break;
2375
Andre Guedesf39799f2012-02-17 20:39:35 -03002376 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002377 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002378 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002379
Johan Hedberg14a53662011-04-27 10:29:56 -04002380 if (err < 0)
2381 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002382 else
2383 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002384
2385failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002386 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002387 return err;
2388}
2389
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002390static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002391 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002392{
Johan Hedbergd9306502012-02-20 23:25:18 +02002393 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002394 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002395 struct hci_cp_remote_name_req_cancel cp;
2396 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002397 int err;
2398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002399 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002400
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002401 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002402
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002403 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002404 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002405 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2406 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002407 goto unlock;
2408 }
2409
2410 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002411 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002412 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2413 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002414 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002415 }
2416
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002417 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002418 if (!cmd) {
2419 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002420 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002421 }
2422
Andre Guedese0d9727e2012-03-20 15:15:36 -03002423 switch (hdev->discovery.state) {
2424 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002425 if (test_bit(HCI_INQUIRY, &hdev->flags))
2426 err = hci_cancel_inquiry(hdev);
2427 else
2428 err = hci_cancel_le_scan(hdev);
2429
Andre Guedese0d9727e2012-03-20 15:15:36 -03002430 break;
2431
2432 case DISCOVERY_RESOLVING:
2433 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002434 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002435 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002436 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002437 err = cmd_complete(sk, hdev->id,
2438 MGMT_OP_STOP_DISCOVERY, 0,
2439 &mgmt_cp->type,
2440 sizeof(mgmt_cp->type));
2441 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2442 goto unlock;
2443 }
2444
2445 bacpy(&cp.bdaddr, &e->data.bdaddr);
2446 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2447 sizeof(cp), &cp);
2448
2449 break;
2450
2451 default:
2452 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2453 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002454 }
2455
Johan Hedberg14a53662011-04-27 10:29:56 -04002456 if (err < 0)
2457 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002458 else
2459 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002460
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002461unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002462 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002463 return err;
2464}
2465
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002466static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002467 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002468{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002469 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002470 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002471 int err;
2472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002473 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002474
Johan Hedberg561aafb2012-01-04 13:31:59 +02002475 hci_dev_lock(hdev);
2476
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002477 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002478 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002479 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002480 goto failed;
2481 }
2482
Johan Hedberga198e7b2012-02-17 14:27:06 +02002483 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002484 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002485 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002486 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002487 goto failed;
2488 }
2489
2490 if (cp->name_known) {
2491 e->name_state = NAME_KNOWN;
2492 list_del(&e->list);
2493 } else {
2494 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002495 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002496 }
2497
2498 err = 0;
2499
2500failed:
2501 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002502 return err;
2503}
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002508 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002509 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002510 int err;
2511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002513
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002514 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002515
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002516 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002517 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002518 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002519 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002520 status = 0;
2521
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002522 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002523 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002526
2527 return err;
2528}
2529
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002530static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002531 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002532{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002533 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002534 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002535 int err;
2536
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002537 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002538
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002539 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002540
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002541 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002542 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002543 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002544 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002545 status = 0;
2546
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002547 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002548 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002549
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002550 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002551
2552 return err;
2553}
2554
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002555static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2556 u16 len)
2557{
2558 struct mgmt_cp_set_device_id *cp = data;
2559 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002560 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002561
2562 BT_DBG("%s", hdev->name);
2563
Szymon Jancc72d4b82012-03-16 16:02:57 +01002564 source = __le16_to_cpu(cp->source);
2565
2566 if (source > 0x0002)
2567 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2568 MGMT_STATUS_INVALID_PARAMS);
2569
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002570 hci_dev_lock(hdev);
2571
Szymon Jancc72d4b82012-03-16 16:02:57 +01002572 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002573 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2574 hdev->devid_product = __le16_to_cpu(cp->product);
2575 hdev->devid_version = __le16_to_cpu(cp->version);
2576
2577 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2578
2579 update_eir(hdev);
2580
2581 hci_dev_unlock(hdev);
2582
2583 return err;
2584}
2585
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002586static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002587 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002588{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002589 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002590 struct hci_cp_write_page_scan_activity acp;
2591 u8 type;
2592 int err;
2593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002594 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002595
Johan Hedberg5400c042012-02-21 16:40:33 +02002596 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002597 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002598 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002599
2600 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002601 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002602 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002603
2604 hci_dev_lock(hdev);
2605
Johan Hedbergf7c68692011-12-15 00:47:36 +02002606 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002607 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002608
Johan Hedberg83ce9a062012-06-28 13:44:30 +03002609 /* 160 msec page scan interval */
2610 acp.interval = __constant_cpu_to_le16(0x0100);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002611 } else {
2612 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002613
2614 /* default 1.28 sec page scan */
2615 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002616 }
2617
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002618 /* default 11.25 msec page scan window */
2619 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002620
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002621 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2622 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002623 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002624 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002625 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002626 goto done;
2627 }
2628
2629 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2630 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002631 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002632 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002633 goto done;
2634 }
2635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002636 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002637 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002638done:
2639 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002640 return err;
2641}
2642
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002643static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002644 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002645{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002646 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2647 u16 key_count, expected_len;
2648 int i;
2649
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002650 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002651
2652 expected_len = sizeof(*cp) + key_count *
2653 sizeof(struct mgmt_ltk_info);
2654 if (expected_len != len) {
2655 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002656 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002657 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002658 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002659 }
2660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002661 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002662
2663 hci_dev_lock(hdev);
2664
2665 hci_smp_ltks_clear(hdev);
2666
2667 for (i = 0; i < key_count; i++) {
2668 struct mgmt_ltk_info *key = &cp->keys[i];
2669 u8 type;
2670
2671 if (key->master)
2672 type = HCI_SMP_LTK;
2673 else
2674 type = HCI_SMP_LTK_SLAVE;
2675
Hemant Gupta4596fde2012-04-16 14:57:40 +05302676 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002677 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002678 type, 0, key->authenticated, key->val,
2679 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002680 }
2681
2682 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002683
2684 return 0;
2685}
2686
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002687static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002688 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2689 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002690 bool var_len;
2691 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002692} mgmt_handlers[] = {
2693 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002694 { read_version, false, MGMT_READ_VERSION_SIZE },
2695 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2696 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2697 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2698 { set_powered, false, MGMT_SETTING_SIZE },
2699 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2700 { set_connectable, false, MGMT_SETTING_SIZE },
2701 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2702 { set_pairable, false, MGMT_SETTING_SIZE },
2703 { set_link_security, false, MGMT_SETTING_SIZE },
2704 { set_ssp, false, MGMT_SETTING_SIZE },
2705 { set_hs, false, MGMT_SETTING_SIZE },
2706 { set_le, false, MGMT_SETTING_SIZE },
2707 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2708 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2709 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2710 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2711 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2712 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2713 { disconnect, false, MGMT_DISCONNECT_SIZE },
2714 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2715 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2716 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2717 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2718 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2719 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2720 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2721 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2722 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2723 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2724 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2725 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2726 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2727 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2728 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2729 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2730 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2731 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2732 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002733 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002734};
2735
2736
Johan Hedberg03811012010-12-08 00:21:06 +02002737int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2738{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002739 void *buf;
2740 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002741 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002742 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002743 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002744 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002745 int err;
2746
2747 BT_DBG("got %zu bytes", msglen);
2748
2749 if (msglen < sizeof(*hdr))
2750 return -EINVAL;
2751
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002752 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002753 if (!buf)
2754 return -ENOMEM;
2755
2756 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2757 err = -EFAULT;
2758 goto done;
2759 }
2760
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002761 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002762 opcode = __le16_to_cpu(hdr->opcode);
2763 index = __le16_to_cpu(hdr->index);
2764 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002765
2766 if (len != msglen - sizeof(*hdr)) {
2767 err = -EINVAL;
2768 goto done;
2769 }
2770
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002771 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002772 hdev = hci_dev_get(index);
2773 if (!hdev) {
2774 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002775 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002776 goto done;
2777 }
2778 }
2779
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002780 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002781 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002782 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002783 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002784 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002785 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002786 }
2787
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002788 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002789 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002790 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002791 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002792 goto done;
2793 }
2794
Johan Hedbergbe22b542012-03-01 22:24:41 +02002795 handler = &mgmt_handlers[opcode];
2796
2797 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002798 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002799 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002800 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002801 goto done;
2802 }
2803
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002804 if (hdev)
2805 mgmt_init_hdev(sk, hdev);
2806
2807 cp = buf + sizeof(*hdr);
2808
Johan Hedbergbe22b542012-03-01 22:24:41 +02002809 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002810 if (err < 0)
2811 goto done;
2812
Johan Hedberg03811012010-12-08 00:21:06 +02002813 err = msglen;
2814
2815done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002816 if (hdev)
2817 hci_dev_put(hdev);
2818
Johan Hedberg03811012010-12-08 00:21:06 +02002819 kfree(buf);
2820 return err;
2821}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002822
Johan Hedbergb24752f2011-11-03 14:40:33 +02002823static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2824{
2825 u8 *status = data;
2826
2827 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2828 mgmt_pending_remove(cmd);
2829}
2830
Johan Hedberg744cf192011-11-08 20:40:14 +02002831int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002832{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002833 if (!mgmt_valid_hdev(hdev))
2834 return -ENOTSUPP;
2835
Johan Hedberg744cf192011-11-08 20:40:14 +02002836 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002837}
2838
Johan Hedberg744cf192011-11-08 20:40:14 +02002839int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002840{
Johan Hedberg5f159032012-03-02 03:13:19 +02002841 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002842
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002843 if (!mgmt_valid_hdev(hdev))
2844 return -ENOTSUPP;
2845
Johan Hedberg744cf192011-11-08 20:40:14 +02002846 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002847
Johan Hedberg744cf192011-11-08 20:40:14 +02002848 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002849}
2850
Johan Hedberg73f22f62010-12-29 16:00:25 +02002851struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002852 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002853 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002854 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002855};
2856
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002857static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002858{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002859 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002860
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002861 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002862
2863 list_del(&cmd->list);
2864
2865 if (match->sk == NULL) {
2866 match->sk = cmd->sk;
2867 sock_hold(match->sk);
2868 }
2869
2870 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002871}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002872
Johan Hedberg744cf192011-11-08 20:40:14 +02002873int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002874{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002875 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002876 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002877
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002878 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2879 return 0;
2880
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002881 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002882
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002883 if (powered) {
2884 u8 scan = 0;
2885
2886 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2887 scan |= SCAN_PAGE;
2888 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2889 scan |= SCAN_INQUIRY;
2890
2891 if (scan)
2892 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002893
2894 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002895 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002896 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002897 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002898 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002899 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002900 }
2901
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002902 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002903
2904 if (match.sk)
2905 sock_put(match.sk);
2906
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002907 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002908}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002909
Johan Hedberg744cf192011-11-08 20:40:14 +02002910int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002911{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002912 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002913 bool changed = false;
2914 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002915
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002916 if (discoverable) {
2917 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2918 changed = true;
2919 } else {
2920 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2921 changed = true;
2922 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002923
Johan Hedberged9b5f22012-02-21 20:47:06 +02002924 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002925 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002926
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002927 if (changed)
2928 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002929
Johan Hedberg73f22f62010-12-29 16:00:25 +02002930 if (match.sk)
2931 sock_put(match.sk);
2932
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002933 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002934}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002935
Johan Hedberg744cf192011-11-08 20:40:14 +02002936int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002937{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002938 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002939 bool changed = false;
2940 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002941
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002942 if (connectable) {
2943 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2944 changed = true;
2945 } else {
2946 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2947 changed = true;
2948 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002949
Johan Hedberged9b5f22012-02-21 20:47:06 +02002950 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002951 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002952
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002953 if (changed)
2954 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002955
2956 if (match.sk)
2957 sock_put(match.sk);
2958
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002959 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002960}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002961
Johan Hedberg744cf192011-11-08 20:40:14 +02002962int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002963{
Johan Hedbergca69b792011-11-11 18:10:00 +02002964 u8 mgmt_err = mgmt_status(status);
2965
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002966 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002967 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002968 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002969
2970 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002971 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002972 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002973
2974 return 0;
2975}
2976
Cristian Chilipirea53168e52012-05-09 08:44:52 +03002977int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2978 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002979{
Johan Hedberg86742e12011-11-07 23:13:38 +02002980 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002981
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002982 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002983
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002984 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002985 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03002986 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002987 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03002988 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002989 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002990
Johan Hedberg744cf192011-11-08 20:40:14 +02002991 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002992}
Johan Hedbergf7520542011-01-20 12:34:39 +02002993
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002994int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2995{
2996 struct mgmt_ev_new_long_term_key ev;
2997
2998 memset(&ev, 0, sizeof(ev));
2999
3000 ev.store_hint = persistent;
3001 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003002 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003003 ev.key.authenticated = key->authenticated;
3004 ev.key.enc_size = key->enc_size;
3005 ev.key.ediv = key->ediv;
3006
3007 if (key->type == HCI_SMP_LTK)
3008 ev.key.master = 1;
3009
3010 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3011 memcpy(ev.key.val, key->val, sizeof(key->val));
3012
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3014 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003015}
3016
Johan Hedbergafc747a2012-01-15 18:11:07 +02003017int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3019 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003020{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003021 char buf[512];
3022 struct mgmt_ev_device_connected *ev = (void *) buf;
3023 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003024
Johan Hedbergb644ba32012-01-17 21:48:47 +02003025 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003026 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003027
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003028 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003029
Johan Hedbergb644ba32012-01-17 21:48:47 +02003030 if (name_len > 0)
3031 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003032 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003033
3034 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003035 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003037
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003038 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003039
3040 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003041 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003042}
3043
Johan Hedberg8962ee72011-01-20 12:40:27 +02003044static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3045{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003046 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003047 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003048 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003049
Johan Hedberg88c3df12012-02-09 14:27:38 +02003050 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3051 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003052
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003053 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003054 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003055
3056 *sk = cmd->sk;
3057 sock_hold(*sk);
3058
Johan Hedberga664b5b2011-02-19 12:06:02 -03003059 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003060}
3061
Johan Hedberg124f6e32012-02-09 13:50:12 +02003062static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003063{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003064 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003065 struct mgmt_cp_unpair_device *cp = cmd->param;
3066 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003067
3068 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003069 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3070 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003071
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003072 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3073
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003074 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003075
3076 mgmt_pending_remove(cmd);
3077}
3078
Johan Hedbergafc747a2012-01-15 18:11:07 +02003079int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003080 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003081{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003082 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003083 struct sock *sk = NULL;
3084 int err;
3085
Johan Hedberg744cf192011-11-08 20:40:14 +02003086 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003087
Johan Hedbergf7520542011-01-20 12:34:39 +02003088 bacpy(&ev.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003089 ev.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003090
Johan Hedbergafc747a2012-01-15 18:11:07 +02003091 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003092 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003093
3094 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003095 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003096
Johan Hedberg124f6e32012-02-09 13:50:12 +02003097 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003098 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003099
Johan Hedberg8962ee72011-01-20 12:40:27 +02003100 return err;
3101}
3102
Johan Hedberg88c3df12012-02-09 14:27:38 +02003103int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003104 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003105{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003106 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003107 struct pending_cmd *cmd;
3108 int err;
3109
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003110 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003111 if (!cmd)
3112 return -ENOENT;
3113
Johan Hedberg88c3df12012-02-09 14:27:38 +02003114 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003115 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003116
Johan Hedberg88c3df12012-02-09 14:27:38 +02003117 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003118 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003119
Johan Hedberga664b5b2011-02-19 12:06:02 -03003120 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003121
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003122 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003123 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003124 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003125}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003126
Johan Hedberg48264f02011-11-09 13:58:58 +02003127int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003128 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003129{
3130 struct mgmt_ev_connect_failed ev;
3131
Johan Hedberg4c659c32011-11-07 23:13:39 +02003132 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003133 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003134 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003135
Johan Hedberg744cf192011-11-08 20:40:14 +02003136 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003137}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003138
Johan Hedberg744cf192011-11-08 20:40:14 +02003139int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003140{
3141 struct mgmt_ev_pin_code_request ev;
3142
Johan Hedbergd8457692012-02-17 14:24:57 +02003143 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003144 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003145 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003146
Johan Hedberg744cf192011-11-08 20:40:14 +02003147 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003148 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003149}
3150
Johan Hedberg744cf192011-11-08 20:40:14 +02003151int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003152 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003153{
3154 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003155 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003156 int err;
3157
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003158 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003159 if (!cmd)
3160 return -ENOENT;
3161
Johan Hedbergd8457692012-02-17 14:24:57 +02003162 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003163 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003164
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003165 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003166 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003167
Johan Hedberga664b5b2011-02-19 12:06:02 -03003168 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003169
3170 return err;
3171}
3172
Johan Hedberg744cf192011-11-08 20:40:14 +02003173int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003174 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003175{
3176 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003177 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003178 int err;
3179
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003180 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003181 if (!cmd)
3182 return -ENOENT;
3183
Johan Hedbergd8457692012-02-17 14:24:57 +02003184 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003185 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003186
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003187 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003188 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003189
Johan Hedberga664b5b2011-02-19 12:06:02 -03003190 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003191
3192 return err;
3193}
Johan Hedberga5c29682011-02-19 12:05:57 -03003194
Johan Hedberg744cf192011-11-08 20:40:14 +02003195int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003196 u8 link_type, u8 addr_type, __le32 value,
3197 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003198{
3199 struct mgmt_ev_user_confirm_request ev;
3200
Johan Hedberg744cf192011-11-08 20:40:14 +02003201 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003202
Johan Hedberg272d90d2012-02-09 15:26:12 +02003203 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003204 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003205 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003206 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003207
Johan Hedberg744cf192011-11-08 20:40:14 +02003208 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003209 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003210}
3211
Johan Hedberg272d90d2012-02-09 15:26:12 +02003212int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003213 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003214{
3215 struct mgmt_ev_user_passkey_request ev;
3216
3217 BT_DBG("%s", hdev->name);
3218
Johan Hedberg272d90d2012-02-09 15:26:12 +02003219 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003220 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003221
3222 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003223 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003224}
3225
Brian Gix0df4c182011-11-16 13:53:13 -08003226static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003227 u8 link_type, u8 addr_type, u8 status,
3228 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003229{
3230 struct pending_cmd *cmd;
3231 struct mgmt_rp_user_confirm_reply rp;
3232 int err;
3233
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003234 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003235 if (!cmd)
3236 return -ENOENT;
3237
Johan Hedberg272d90d2012-02-09 15:26:12 +02003238 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003239 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003240 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003241 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003242
Johan Hedberga664b5b2011-02-19 12:06:02 -03003243 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003244
3245 return err;
3246}
3247
Johan Hedberg744cf192011-11-08 20:40:14 +02003248int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003249 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003250{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003251 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003252 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003253}
3254
Johan Hedberg272d90d2012-02-09 15:26:12 +02003255int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003256 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003257{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003258 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003259 status,
3260 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003261}
Johan Hedberg2a611692011-02-19 12:06:00 -03003262
Brian Gix604086b2011-11-23 08:28:33 -08003263int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003264 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003265{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003266 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003267 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003268}
3269
Johan Hedberg272d90d2012-02-09 15:26:12 +02003270int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003271 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003272{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003273 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003274 status,
3275 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003276}
3277
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003278int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003279 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003280{
3281 struct mgmt_ev_auth_failed ev;
3282
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003283 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003284 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003285 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003286
Johan Hedberg744cf192011-11-08 20:40:14 +02003287 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003288}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003289
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003290int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3291{
3292 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003293 bool changed = false;
3294 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003295
3296 if (status) {
3297 u8 mgmt_err = mgmt_status(status);
3298 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003299 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003300 return 0;
3301 }
3302
Johan Hedberg47990ea2012-02-22 11:58:37 +02003303 if (test_bit(HCI_AUTH, &hdev->flags)) {
3304 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3305 changed = true;
3306 } else {
3307 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3308 changed = true;
3309 }
3310
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003311 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003312 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003313
Johan Hedberg47990ea2012-02-22 11:58:37 +02003314 if (changed)
3315 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003316
3317 if (match.sk)
3318 sock_put(match.sk);
3319
3320 return err;
3321}
3322
Johan Hedbergcacaf522012-02-21 00:52:42 +02003323static int clear_eir(struct hci_dev *hdev)
3324{
3325 struct hci_cp_write_eir cp;
3326
3327 if (!(hdev->features[6] & LMP_EXT_INQ))
3328 return 0;
3329
Johan Hedbergc80da272012-02-22 15:38:48 +02003330 memset(hdev->eir, 0, sizeof(hdev->eir));
3331
Johan Hedbergcacaf522012-02-21 00:52:42 +02003332 memset(&cp, 0, sizeof(cp));
3333
3334 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3335}
3336
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003337int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003338{
3339 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003340 bool changed = false;
3341 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003342
3343 if (status) {
3344 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003345
3346 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003347 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003348 err = new_settings(hdev, NULL);
3349
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003350 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3351 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003352
3353 return err;
3354 }
3355
3356 if (enable) {
3357 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3358 changed = true;
3359 } else {
3360 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3361 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003362 }
3363
3364 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3365
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003366 if (changed)
3367 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003368
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003369 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003370 sock_put(match.sk);
3371
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003372 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3373 update_eir(hdev);
3374 else
3375 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003376
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003377 return err;
3378}
3379
Johan Hedberg90e70452012-02-23 23:09:40 +02003380static void class_rsp(struct pending_cmd *cmd, void *data)
3381{
3382 struct cmd_lookup *match = data;
3383
3384 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003385 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003386
3387 list_del(&cmd->list);
3388
3389 if (match->sk == NULL) {
3390 match->sk = cmd->sk;
3391 sock_hold(match->sk);
3392 }
3393
3394 mgmt_pending_free(cmd);
3395}
3396
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003397int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003398 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003399{
Johan Hedberg90e70452012-02-23 23:09:40 +02003400 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3401 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003402
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003403 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3404
Johan Hedberg90e70452012-02-23 23:09:40 +02003405 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3406 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3407 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3408
3409 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003410 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3411 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003412
3413 if (match.sk)
3414 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003415
3416 return err;
3417}
3418
Johan Hedberg744cf192011-11-08 20:40:14 +02003419int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003420{
3421 struct pending_cmd *cmd;
3422 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003423 bool changed = false;
3424 int err = 0;
3425
3426 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3427 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3428 changed = true;
3429 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003430
3431 memset(&ev, 0, sizeof(ev));
3432 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003433 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003434
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003435 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003436 if (!cmd)
3437 goto send_event;
3438
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003439 /* Always assume that either the short or the complete name has
3440 * changed if there was a pending mgmt command */
3441 changed = true;
3442
Johan Hedbergb312b1612011-03-16 14:29:37 +02003443 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003444 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003445 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003446 goto failed;
3447 }
3448
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003449 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003450 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003451 if (err < 0)
3452 goto failed;
3453
3454send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003455 if (changed)
3456 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003457 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003458
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003459 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003460
3461failed:
3462 if (cmd)
3463 mgmt_pending_remove(cmd);
3464 return err;
3465}
Szymon Jancc35938b2011-03-22 13:12:21 +01003466
Johan Hedberg744cf192011-11-08 20:40:14 +02003467int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003468 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003469{
3470 struct pending_cmd *cmd;
3471 int err;
3472
Johan Hedberg744cf192011-11-08 20:40:14 +02003473 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003474
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003475 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003476 if (!cmd)
3477 return -ENOENT;
3478
3479 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003480 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3481 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003482 } else {
3483 struct mgmt_rp_read_local_oob_data rp;
3484
3485 memcpy(rp.hash, hash, sizeof(rp.hash));
3486 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3487
Johan Hedberg744cf192011-11-08 20:40:14 +02003488 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003489 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3490 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003491 }
3492
3493 mgmt_pending_remove(cmd);
3494
3495 return err;
3496}
Johan Hedberge17acd42011-03-30 23:57:16 +03003497
Johan Hedberg06199cf2012-02-22 16:37:11 +02003498int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3499{
3500 struct cmd_lookup match = { NULL, hdev };
3501 bool changed = false;
3502 int err = 0;
3503
3504 if (status) {
3505 u8 mgmt_err = mgmt_status(status);
3506
3507 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003508 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003509 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003510
Szymon Jancd97dcb62012-03-16 16:02:56 +01003511 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3512 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003513
3514 return err;
3515 }
3516
3517 if (enable) {
3518 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3519 changed = true;
3520 } else {
3521 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3522 changed = true;
3523 }
3524
3525 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3526
3527 if (changed)
3528 err = new_settings(hdev, match.sk);
3529
3530 if (match.sk)
3531 sock_put(match.sk);
3532
3533 return err;
3534}
3535
Johan Hedberg48264f02011-11-09 13:58:58 +02003536int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003537 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3538 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003539{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003540 char buf[512];
3541 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003542 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003543
Johan Hedberg1dc06092012-01-15 21:01:23 +02003544 /* Leave 5 bytes for a potential CoD field */
3545 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003546 return -EINVAL;
3547
Johan Hedberg1dc06092012-01-15 21:01:23 +02003548 memset(buf, 0, sizeof(buf));
3549
Johan Hedberge319d2e2012-01-15 19:51:59 +02003550 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003551 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003552 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003553 if (cfm_name)
Andrei Emeltchenko33cef262012-06-18 13:03:46 +03003554 ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003555 if (!ssp)
Andrei Emeltchenko33cef262012-06-18 13:03:46 +03003556 ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003557
Johan Hedberg1dc06092012-01-15 21:01:23 +02003558 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003559 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003560
Johan Hedberg1dc06092012-01-15 21:01:23 +02003561 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3562 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003563 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003564
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003565 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003566 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003567
Johan Hedberge319d2e2012-01-15 19:51:59 +02003568 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003569}
Johan Hedberga88a9652011-03-30 13:18:12 +03003570
Johan Hedbergb644ba32012-01-17 21:48:47 +02003571int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003572 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003573{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003574 struct mgmt_ev_device_found *ev;
3575 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3576 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003577
Johan Hedbergb644ba32012-01-17 21:48:47 +02003578 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003579
Johan Hedbergb644ba32012-01-17 21:48:47 +02003580 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003581
Johan Hedbergb644ba32012-01-17 21:48:47 +02003582 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003583 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003584 ev->rssi = rssi;
3585
3586 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003587 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003588
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003589 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003590
Johan Hedberg053c7e02012-02-04 00:06:00 +02003591 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003592 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003593}
Johan Hedberg314b2382011-04-27 10:29:57 -04003594
Andre Guedes7a135102011-11-09 17:14:25 -03003595int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003596{
3597 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003598 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003599 int err;
3600
Andre Guedes203159d2012-02-13 15:41:01 -03003601 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3602
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003603 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003604 if (!cmd)
3605 return -ENOENT;
3606
Johan Hedbergf808e162012-02-19 12:52:07 +02003607 type = hdev->discovery.type;
3608
3609 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003610 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003611 mgmt_pending_remove(cmd);
3612
3613 return err;
3614}
3615
Andre Guedese6d465c2011-11-09 17:14:26 -03003616int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3617{
3618 struct pending_cmd *cmd;
3619 int err;
3620
3621 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3622 if (!cmd)
3623 return -ENOENT;
3624
Johan Hedbergd9306502012-02-20 23:25:18 +02003625 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003626 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003627 mgmt_pending_remove(cmd);
3628
3629 return err;
3630}
Johan Hedberg314b2382011-04-27 10:29:57 -04003631
Johan Hedberg744cf192011-11-08 20:40:14 +02003632int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003633{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003634 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003635 struct pending_cmd *cmd;
3636
Andre Guedes343fb142011-11-22 17:14:19 -03003637 BT_DBG("%s discovering %u", hdev->name, discovering);
3638
Johan Hedberg164a6e72011-11-01 17:06:44 +02003639 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003640 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003641 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003642 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003643
3644 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003645 u8 type = hdev->discovery.type;
3646
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003647 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3648 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003649 mgmt_pending_remove(cmd);
3650 }
3651
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003652 memset(&ev, 0, sizeof(ev));
3653 ev.type = hdev->discovery.type;
3654 ev.discovering = discovering;
3655
3656 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003657}
Antti Julku5e762442011-08-25 16:48:02 +03003658
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003659int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003660{
3661 struct pending_cmd *cmd;
3662 struct mgmt_ev_device_blocked ev;
3663
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003664 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003665
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003666 bacpy(&ev.addr.bdaddr, bdaddr);
3667 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003668
Johan Hedberg744cf192011-11-08 20:40:14 +02003669 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003670 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003671}
3672
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003673int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003674{
3675 struct pending_cmd *cmd;
3676 struct mgmt_ev_device_unblocked ev;
3677
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003678 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003679
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003680 bacpy(&ev.addr.bdaddr, bdaddr);
3681 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003682
Johan Hedberg744cf192011-11-08 20:40:14 +02003683 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003684 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003685}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003686
3687module_param(enable_hs, bool, 0644);
3688MODULE_PARM_DESC(enable_hs, "Enable High Speed support");