blob: 958f764cc6ab6d8c5f8ddb9b70548deb6d06a106 [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
196static u8 mgmt_status(u8 hci_status)
197{
198 if (hci_status < ARRAY_SIZE(mgmt_status_table))
199 return mgmt_status_table[hci_status];
200
201 return MGMT_STATUS_FAILED;
202}
203
Szymon Janc4e51eae2011-02-25 19:05:48 +0100204static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200205{
206 struct sk_buff *skb;
207 struct mgmt_hdr *hdr;
208 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300209 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210
Szymon Janc34eb5252011-02-28 14:10:08 +0100211 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
213 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
214 if (!skb)
215 return -ENOMEM;
216
217 hdr = (void *) skb_put(skb, sizeof(*hdr));
218
219 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100220 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200221 hdr->len = cpu_to_le16(sizeof(*ev));
222
223 ev = (void *) skb_put(skb, sizeof(*ev));
224 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200225 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300227 err = sock_queue_rcv_skb(sk, skb);
228 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200229 kfree_skb(skb);
230
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200232}
233
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200234static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300235 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200236{
237 struct sk_buff *skb;
238 struct mgmt_hdr *hdr;
239 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300240 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200241
242 BT_DBG("sock %p", sk);
243
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200245 if (!skb)
246 return -ENOMEM;
247
248 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200249
Johan Hedberg02d98122010-12-13 21:07:04 +0200250 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100251 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200252 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200253
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200255 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200256 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100257
258 if (rp)
259 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200260
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300261 err = sock_queue_rcv_skb(sk, skb);
262 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200263 kfree_skb(skb);
264
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100265 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200266}
267
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300268static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
269 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200270{
271 struct mgmt_rp_read_version rp;
272
273 BT_DBG("sock %p", sk);
274
275 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200276 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200277
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200278 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300279 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200280}
281
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300282static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
283 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200284{
285 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200286 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200288 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200300 rp->num_commands = __constant_cpu_to_le16(num_commands);
301 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300310 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200311 kfree(rp);
312
313 return err;
314}
315
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300316static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
317 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200319 struct mgmt_rp_read_index_list *rp;
320 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200321 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200322 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200323 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200324 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325
326 BT_DBG("sock %p", sk);
327
328 read_lock(&hci_dev_list_lock);
329
330 count = 0;
331 list_for_each(p, &hci_dev_list) {
332 count++;
333 }
334
Johan Hedberga38528f2011-01-22 06:46:43 +0200335 rp_len = sizeof(*rp) + (2 * count);
336 rp = kmalloc(rp_len, GFP_ATOMIC);
337 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100338 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200339 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100340 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200342 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343
344 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200345 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200346 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200347 continue;
348
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200349 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 BT_DBG("Added hci%u", d->id);
351 }
352
353 read_unlock(&hci_dev_list_lock);
354
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200355 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300356 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357
Johan Hedberga38528f2011-01-22 06:46:43 +0200358 kfree(rp);
359
360 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200361}
362
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200364{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 settings |= MGMT_SETTING_POWERED;
368 settings |= MGMT_SETTING_CONNECTABLE;
369 settings |= MGMT_SETTING_FAST_CONNECTABLE;
370 settings |= MGMT_SETTING_DISCOVERABLE;
371 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200372
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 if (hdev->features[6] & LMP_SIMPLE_PAIR)
374 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200375
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 if (!(hdev->features[4] & LMP_NO_BREDR)) {
377 settings |= MGMT_SETTING_BREDR;
378 settings |= MGMT_SETTING_LINK_SECURITY;
379 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200380
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100381 if (enable_hs)
382 settings |= MGMT_SETTING_HS;
383
Marcel Holtmann9d428202012-05-03 07:12:31 +0200384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200386
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387 return settings;
388}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200389
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200390static u32 get_current_settings(struct hci_dev *hdev)
391{
392 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200393
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200394 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100395 settings |= MGMT_SETTING_POWERED;
396
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200397 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200398 settings |= MGMT_SETTING_CONNECTABLE;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_DISCOVERABLE;
402
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200403 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200404 settings |= MGMT_SETTING_PAIRABLE;
405
406 if (!(hdev->features[4] & LMP_NO_BREDR))
407 settings |= MGMT_SETTING_BREDR;
408
Johan Hedberg06199cf2012-02-22 16:37:11 +0200409 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200411
Johan Hedberg47990ea2012-02-22 11:58:37 +0200412 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200414
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200415 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200417
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200418 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
419 settings |= MGMT_SETTING_HS;
420
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200422}
423
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300424#define PNP_INFO_SVCLASS_ID 0x1200
425
426static u8 bluetooth_base_uuid[] = {
427 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
428 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
429};
430
431static u16 get_uuid16(u8 *uuid128)
432{
433 u32 val;
434 int i;
435
436 for (i = 0; i < 12; i++) {
437 if (bluetooth_base_uuid[i] != uuid128[i])
438 return 0;
439 }
440
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200441 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300442 if (val > 0xffff)
443 return 0;
444
445 return (u16) val;
446}
447
448static void create_eir(struct hci_dev *hdev, u8 *data)
449{
450 u8 *ptr = data;
451 u16 eir_len = 0;
452 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
453 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200454 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300455 size_t name_len;
456
457 name_len = strlen(hdev->dev_name);
458
459 if (name_len > 0) {
460 /* EIR Data type */
461 if (name_len > 48) {
462 name_len = 48;
463 ptr[1] = EIR_NAME_SHORT;
464 } else
465 ptr[1] = EIR_NAME_COMPLETE;
466
467 /* EIR Data length */
468 ptr[0] = name_len + 1;
469
470 memcpy(ptr + 2, hdev->dev_name, name_len);
471
472 eir_len += (name_len + 2);
473 ptr += (name_len + 2);
474 }
475
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700476 if (hdev->inq_tx_power) {
477 ptr[0] = 2;
478 ptr[1] = EIR_TX_POWER;
479 ptr[2] = (u8) hdev->inq_tx_power;
480
481 eir_len += 3;
482 ptr += 3;
483 }
484
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700485 if (hdev->devid_source > 0) {
486 ptr[0] = 9;
487 ptr[1] = EIR_DEVICE_ID;
488
489 put_unaligned_le16(hdev->devid_source, ptr + 2);
490 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
491 put_unaligned_le16(hdev->devid_product, ptr + 6);
492 put_unaligned_le16(hdev->devid_version, ptr + 8);
493
494 eir_len += 10;
495 ptr += 10;
496 }
497
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300498 memset(uuid16_list, 0, sizeof(uuid16_list));
499
500 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200501 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300502 u16 uuid16;
503
504 uuid16 = get_uuid16(uuid->uuid);
505 if (uuid16 == 0)
506 return;
507
508 if (uuid16 < 0x1100)
509 continue;
510
511 if (uuid16 == PNP_INFO_SVCLASS_ID)
512 continue;
513
514 /* Stop if not enough space to put next UUID */
515 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
516 truncated = 1;
517 break;
518 }
519
520 /* Check for duplicates */
521 for (i = 0; uuid16_list[i] != 0; i++)
522 if (uuid16_list[i] == uuid16)
523 break;
524
525 if (uuid16_list[i] == 0) {
526 uuid16_list[i] = uuid16;
527 eir_len += sizeof(u16);
528 }
529 }
530
531 if (uuid16_list[0] != 0) {
532 u8 *length = ptr;
533
534 /* EIR Data type */
535 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
536
537 ptr += 2;
538 eir_len += 2;
539
540 for (i = 0; uuid16_list[i] != 0; i++) {
541 *ptr++ = (uuid16_list[i] & 0x00ff);
542 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
543 }
544
545 /* EIR Data length */
546 *length = (i * sizeof(u16)) + 1;
547 }
548}
549
550static int update_eir(struct hci_dev *hdev)
551{
552 struct hci_cp_write_eir cp;
553
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200554 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200555 return 0;
556
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300557 if (!(hdev->features[6] & LMP_EXT_INQ))
558 return 0;
559
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200560 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300561 return 0;
562
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200563 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 return 0;
565
566 memset(&cp, 0, sizeof(cp));
567
568 create_eir(hdev, cp.data);
569
570 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
571 return 0;
572
573 memcpy(hdev->eir, cp.data, sizeof(cp.data));
574
575 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
576}
577
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200578static u8 get_service_classes(struct hci_dev *hdev)
579{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300580 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200581 u8 val = 0;
582
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300583 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200585
586 return val;
587}
588
589static int update_class(struct hci_dev *hdev)
590{
591 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200592 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200593
594 BT_DBG("%s", hdev->name);
595
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200596 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200597 return 0;
598
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200599 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200600 return 0;
601
602 cod[0] = hdev->minor_class;
603 cod[1] = hdev->major_class;
604 cod[2] = get_service_classes(hdev);
605
606 if (memcmp(cod, hdev->dev_class, 3) == 0)
607 return 0;
608
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200609 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
610 if (err == 0)
611 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
612
613 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200614}
615
Johan Hedberg7d785252011-12-15 00:47:39 +0200616static void service_cache_off(struct work_struct *work)
617{
618 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300619 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200620
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200621 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200622 return;
623
624 hci_dev_lock(hdev);
625
626 update_eir(hdev);
627 update_class(hdev);
628
629 hci_dev_unlock(hdev);
630}
631
Johan Hedberg6a919082012-02-28 06:17:26 +0200632static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200633{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200634 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200635 return;
636
Johan Hedberg4f87da82012-03-02 19:55:56 +0200637 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200638
Johan Hedberg4f87da82012-03-02 19:55:56 +0200639 /* Non-mgmt controlled devices get this bit set
640 * implicitly so that pairing works for them, however
641 * for mgmt we require user-space to explicitly enable
642 * it
643 */
644 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200645}
646
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200647static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300648 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200649{
650 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200651
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200652 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200653
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300654 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200655
Johan Hedberg03811012010-12-08 00:21:06 +0200656 memset(&rp, 0, sizeof(rp));
657
Johan Hedberg03811012010-12-08 00:21:06 +0200658 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200659
660 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200661 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662
663 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
664 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
665
666 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200667
668 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200669 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200670
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300671 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200672
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200673 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300674 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200675}
676
677static void mgmt_pending_free(struct pending_cmd *cmd)
678{
679 sock_put(cmd->sk);
680 kfree(cmd->param);
681 kfree(cmd);
682}
683
684static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300685 struct hci_dev *hdev, void *data,
686 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200687{
688 struct pending_cmd *cmd;
689
690 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
691 if (!cmd)
692 return NULL;
693
694 cmd->opcode = opcode;
695 cmd->index = hdev->id;
696
697 cmd->param = kmalloc(len, GFP_ATOMIC);
698 if (!cmd->param) {
699 kfree(cmd);
700 return NULL;
701 }
702
703 if (data)
704 memcpy(cmd->param, data, len);
705
706 cmd->sk = sk;
707 sock_hold(sk);
708
709 list_add(&cmd->list, &hdev->mgmt_pending);
710
711 return cmd;
712}
713
714static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300715 void (*cb)(struct pending_cmd *cmd,
716 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300717 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200718{
719 struct list_head *p, *n;
720
721 list_for_each_safe(p, n, &hdev->mgmt_pending) {
722 struct pending_cmd *cmd;
723
724 cmd = list_entry(p, struct pending_cmd, list);
725
726 if (opcode > 0 && cmd->opcode != opcode)
727 continue;
728
729 cb(cmd, data);
730 }
731}
732
733static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
734{
735 struct pending_cmd *cmd;
736
737 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
738 if (cmd->opcode == opcode)
739 return cmd;
740 }
741
742 return NULL;
743}
744
745static void mgmt_pending_remove(struct pending_cmd *cmd)
746{
747 list_del(&cmd->list);
748 mgmt_pending_free(cmd);
749}
750
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200751static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200752{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200753 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200754
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200755 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300756 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200757}
758
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200759static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300760 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200761{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300762 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200763 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200764 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200765
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200766 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200767
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300768 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200769
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100770 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
771 cancel_delayed_work(&hdev->power_off);
772
773 if (cp->val) {
774 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
775 mgmt_powered(hdev, 1);
776 goto failed;
777 }
778 }
779
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200780 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200781 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200782 goto failed;
783 }
784
785 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200786 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300787 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 goto failed;
789 }
790
791 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
792 if (!cmd) {
793 err = -ENOMEM;
794 goto failed;
795 }
796
797 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200798 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200799 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200800 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200801
802 err = 0;
803
804failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300805 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200806 return err;
807}
808
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300809static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
810 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200811{
812 struct sk_buff *skb;
813 struct mgmt_hdr *hdr;
814
815 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
816 if (!skb)
817 return -ENOMEM;
818
819 hdr = (void *) skb_put(skb, sizeof(*hdr));
820 hdr->opcode = cpu_to_le16(event);
821 if (hdev)
822 hdr->index = cpu_to_le16(hdev->id);
823 else
824 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
825 hdr->len = cpu_to_le16(data_len);
826
827 if (data)
828 memcpy(skb_put(skb, data_len), data, data_len);
829
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100830 /* Time stamp */
831 __net_timestamp(skb);
832
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200833 hci_send_to_control(skb, skip_sk);
834 kfree_skb(skb);
835
836 return 0;
837}
838
839static int new_settings(struct hci_dev *hdev, struct sock *skip)
840{
841 __le32 ev;
842
843 ev = cpu_to_le32(get_current_settings(hdev));
844
845 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
846}
847
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200848static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300849 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200850{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300851 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200852 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200853 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200854 u8 scan;
855 int err;
856
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200857 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200858
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700859 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100860 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200861 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300862 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200863
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300864 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200865
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200866 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200867 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300868 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869 goto failed;
870 }
871
872 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300873 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200874 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300875 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200876 goto failed;
877 }
878
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200879 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200880 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300881 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200882 goto failed;
883 }
884
885 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200886 bool changed = false;
887
888 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
889 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
890 changed = true;
891 }
892
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200893 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200894 if (err < 0)
895 goto failed;
896
897 if (changed)
898 err = new_settings(hdev, sk);
899
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200900 goto failed;
901 }
902
903 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100904 if (hdev->discov_timeout > 0) {
905 cancel_delayed_work(&hdev->discov_off);
906 hdev->discov_timeout = 0;
907 }
908
909 if (cp->val && timeout > 0) {
910 hdev->discov_timeout = timeout;
911 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
912 msecs_to_jiffies(hdev->discov_timeout * 1000));
913 }
914
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200915 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200916 goto failed;
917 }
918
919 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
920 if (!cmd) {
921 err = -ENOMEM;
922 goto failed;
923 }
924
925 scan = SCAN_PAGE;
926
927 if (cp->val)
928 scan |= SCAN_INQUIRY;
929 else
930 cancel_delayed_work(&hdev->discov_off);
931
932 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
933 if (err < 0)
934 mgmt_pending_remove(cmd);
935
Johan Hedberg03811012010-12-08 00:21:06 +0200936 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200937 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200938
939failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300940 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200941 return err;
942}
943
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200944static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300945 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200946{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300947 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200948 struct pending_cmd *cmd;
949 u8 scan;
950 int err;
951
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200952 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200953
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300954 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200955
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200956 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200957 bool changed = false;
958
959 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
960 changed = true;
961
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200962 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200963 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200964 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200965 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
966 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
967 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200968
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200969 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200970 if (err < 0)
971 goto failed;
972
973 if (changed)
974 err = new_settings(hdev, sk);
975
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200976 goto failed;
977 }
978
979 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300980 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200981 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300982 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200983 goto failed;
984 }
985
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200986 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200987 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200988 goto failed;
989 }
990
991 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
992 if (!cmd) {
993 err = -ENOMEM;
994 goto failed;
995 }
996
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200997 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200998 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200999 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000 scan = 0;
1001
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001002 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001003 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001004 cancel_delayed_work(&hdev->discov_off);
1005 }
1006
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1008 if (err < 0)
1009 mgmt_pending_remove(cmd);
1010
1011failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001012 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013 return err;
1014}
1015
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001016static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001017 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001018{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001019 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001020 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001022 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001024 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025
1026 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001027 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001028 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001029 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001031 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 if (err < 0)
1033 goto failed;
1034
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001035 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036
1037failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001038 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001039 return err;
1040}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001041
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001042static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1043 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001044{
1045 struct mgmt_mode *cp = data;
1046 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001047 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001048 int err;
1049
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001050 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001051
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001052 hci_dev_lock(hdev);
1053
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001054 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001055 bool changed = false;
1056
1057 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001058 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001059 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1060 changed = true;
1061 }
1062
1063 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1064 if (err < 0)
1065 goto failed;
1066
1067 if (changed)
1068 err = new_settings(hdev, sk);
1069
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001070 goto failed;
1071 }
1072
1073 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001074 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001075 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001076 goto failed;
1077 }
1078
1079 val = !!cp->val;
1080
1081 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1082 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1083 goto failed;
1084 }
1085
1086 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1087 if (!cmd) {
1088 err = -ENOMEM;
1089 goto failed;
1090 }
1091
1092 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1093 if (err < 0) {
1094 mgmt_pending_remove(cmd);
1095 goto failed;
1096 }
1097
1098failed:
1099 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001100 return err;
1101}
1102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001103static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001104{
1105 struct mgmt_mode *cp = data;
1106 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001107 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001108 int err;
1109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001110 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001111
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001112 hci_dev_lock(hdev);
1113
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001114 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001115 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001116 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001117 goto failed;
1118 }
1119
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001120 val = !!cp->val;
1121
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001122 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001123 bool changed = false;
1124
1125 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1126 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1127 changed = true;
1128 }
1129
1130 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1131 if (err < 0)
1132 goto failed;
1133
1134 if (changed)
1135 err = new_settings(hdev, sk);
1136
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001137 goto failed;
1138 }
1139
1140 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001141 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1142 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001143 goto failed;
1144 }
1145
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001146 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1147 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1148 goto failed;
1149 }
1150
1151 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1152 if (!cmd) {
1153 err = -ENOMEM;
1154 goto failed;
1155 }
1156
1157 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1158 if (err < 0) {
1159 mgmt_pending_remove(cmd);
1160 goto failed;
1161 }
1162
1163failed:
1164 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001165 return err;
1166}
1167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001168static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001169{
1170 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001172 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174 if (!enable_hs)
1175 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001176 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177
1178 if (cp->val)
1179 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1180 else
1181 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001183 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001184}
1185
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001186static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001187{
1188 struct mgmt_mode *cp = data;
1189 struct hci_cp_write_le_host_supported hci_cp;
1190 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001191 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001192 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001194 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001195
Johan Hedberg1de028c2012-02-29 19:55:35 -08001196 hci_dev_lock(hdev);
1197
Marcel Holtmann9d428202012-05-03 07:12:31 +02001198 if (!(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001199 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001200 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001201 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202 }
1203
1204 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001205 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001206
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001207 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001208 bool changed = false;
1209
1210 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1211 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1212 changed = true;
1213 }
1214
1215 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1216 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001217 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001218
1219 if (changed)
1220 err = new_settings(hdev, sk);
1221
Johan Hedberg1de028c2012-02-29 19:55:35 -08001222 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001223 }
1224
1225 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001226 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001227 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001228 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001229 }
1230
1231 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1232 if (!cmd) {
1233 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001234 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001235 }
1236
1237 memset(&hci_cp, 0, sizeof(hci_cp));
1238
1239 if (val) {
1240 hci_cp.le = val;
1241 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1242 }
1243
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001244 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1245 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301246 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001247 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001248
Johan Hedberg1de028c2012-02-29 19:55:35 -08001249unlock:
1250 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001251 return err;
1252}
1253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001254static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001256 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001257 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001258 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259 int err;
1260
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001261 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001262
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001263 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001264
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001265 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001266 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001267 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001268 goto failed;
1269 }
1270
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001271 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1272 if (!uuid) {
1273 err = -ENOMEM;
1274 goto failed;
1275 }
1276
1277 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001278 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001279
1280 list_add(&uuid->list, &hdev->uuids);
1281
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001282 err = update_class(hdev);
1283 if (err < 0)
1284 goto failed;
1285
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001286 err = update_eir(hdev);
1287 if (err < 0)
1288 goto failed;
1289
Johan Hedberg90e70452012-02-23 23:09:40 +02001290 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001291 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001292 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001293 goto failed;
1294 }
1295
1296 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301297 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001298 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001299
1300failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001301 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001302 return err;
1303}
1304
Johan Hedberg24b78d02012-02-23 23:24:30 +02001305static bool enable_service_cache(struct hci_dev *hdev)
1306{
1307 if (!hdev_is_powered(hdev))
1308 return false;
1309
1310 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001311 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001312 return true;
1313 }
1314
1315 return false;
1316}
1317
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001318static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001319 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001320{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001321 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001322 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001323 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001324 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 +02001325 int err, found;
1326
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001327 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001329 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001331 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001332 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001333 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001334 goto unlock;
1335 }
1336
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001337 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1338 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001339
Johan Hedberg24b78d02012-02-23 23:24:30 +02001340 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001341 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001342 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001343 goto unlock;
1344 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001345
Johan Hedberg9246a862012-02-23 21:33:16 +02001346 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 }
1348
1349 found = 0;
1350
1351 list_for_each_safe(p, n, &hdev->uuids) {
1352 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1353
1354 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1355 continue;
1356
1357 list_del(&match->list);
1358 found++;
1359 }
1360
1361 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001362 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001363 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001364 goto unlock;
1365 }
1366
Johan Hedberg9246a862012-02-23 21:33:16 +02001367update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001368 err = update_class(hdev);
1369 if (err < 0)
1370 goto unlock;
1371
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001372 err = update_eir(hdev);
1373 if (err < 0)
1374 goto unlock;
1375
Johan Hedberg90e70452012-02-23 23:09:40 +02001376 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001377 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001378 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001379 goto unlock;
1380 }
1381
1382 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301383 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001384 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001385
1386unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001387 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001388 return err;
1389}
1390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001391static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001392 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001393{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001394 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001395 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001396 int err;
1397
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001398 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001400 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001401
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001402 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001403 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001404 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001405 goto unlock;
1406 }
1407
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001408 hdev->major_class = cp->major;
1409 hdev->minor_class = cp->minor;
1410
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001411 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001412 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001413 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001414 goto unlock;
1415 }
1416
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001417 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001418 hci_dev_unlock(hdev);
1419 cancel_delayed_work_sync(&hdev->service_cache);
1420 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001421 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001422 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001423
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001424 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001425 if (err < 0)
1426 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001427
Johan Hedberg90e70452012-02-23 23:09:40 +02001428 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001429 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001430 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001431 goto unlock;
1432 }
1433
1434 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301435 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001436 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001437
Johan Hedbergb5235a62012-02-21 14:32:24 +02001438unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001439 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001440 return err;
1441}
1442
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001443static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001444 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001445{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001446 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001447 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001448 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001449
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001450 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001451
Johan Hedberg86742e12011-11-07 23:13:38 +02001452 expected_len = sizeof(*cp) + key_count *
1453 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001454 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001455 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001456 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001457 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001458 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001459 }
1460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001461 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001462 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001464 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001465
1466 hci_link_keys_clear(hdev);
1467
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001468 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469
1470 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001471 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001472 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001473 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001474
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001475 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001476 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001477
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001478 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001479 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001480 }
1481
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001482 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001483
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001484 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001485
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001486 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001487}
1488
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001489static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001490 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001491{
1492 struct mgmt_ev_device_unpaired ev;
1493
1494 bacpy(&ev.addr.bdaddr, bdaddr);
1495 ev.addr.type = addr_type;
1496
1497 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001498 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001499}
1500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001501static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001502 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001503{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001504 struct mgmt_cp_unpair_device *cp = data;
1505 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001506 struct hci_cp_disconnect dc;
1507 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001509 int err;
1510
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001511 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001512
Johan Hedberga8a1d192011-11-10 15:54:38 +02001513 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001514 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1515 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001516
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001517 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001518 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001519 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001520 goto unlock;
1521 }
1522
Andre Guedes591f47f2012-04-24 21:02:49 -03001523 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001524 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1525 else
1526 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001527
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001528 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001529 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001530 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001531 goto unlock;
1532 }
1533
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001534 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001535 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001536 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001537 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001538 else
1539 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001540 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001541 } else {
1542 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001543 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001544
Johan Hedberga8a1d192011-11-10 15:54:38 +02001545 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001546 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001547 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001548 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001549 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001550 }
1551
Johan Hedberg124f6e32012-02-09 13:50:12 +02001552 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001553 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001554 if (!cmd) {
1555 err = -ENOMEM;
1556 goto unlock;
1557 }
1558
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001559 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001560 dc.reason = 0x13; /* Remote User Terminated Connection */
1561 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1562 if (err < 0)
1563 mgmt_pending_remove(cmd);
1564
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001565unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001566 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001567 return err;
1568}
1569
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001570static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001571 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001572{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001573 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001574 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001575 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001576 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001577 int err;
1578
1579 BT_DBG("");
1580
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001581 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001582
1583 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001584 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001585 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586 goto failed;
1587 }
1588
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001589 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001591 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001592 goto failed;
1593 }
1594
Andre Guedes591f47f2012-04-24 21:02:49 -03001595 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001596 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1597 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001598 else
1599 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001600
Johan Hedberg8962ee72011-01-20 12:40:27 +02001601 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001602 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001603 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001604 goto failed;
1605 }
1606
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001607 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001608 if (!cmd) {
1609 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001610 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001611 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001612
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001613 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001614 dc.reason = 0x13; /* Remote User Terminated Connection */
1615
1616 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1617 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001618 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001619
1620failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001621 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001622 return err;
1623}
1624
Andre Guedes57c14772012-04-24 21:02:50 -03001625static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001626{
1627 switch (link_type) {
1628 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001629 switch (addr_type) {
1630 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001631 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001632
Johan Hedberg48264f02011-11-09 13:58:58 +02001633 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001634 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001635 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001636 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001637
Johan Hedberg4c659c32011-11-07 23:13:39 +02001638 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001639 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001640 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001641 }
1642}
1643
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001644static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1645 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001646{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001647 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001648 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001649 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001650 int err;
1651 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001652
1653 BT_DBG("");
1654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001655 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001656
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001657 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001658 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001659 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001660 goto unlock;
1661 }
1662
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001663 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001664 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1665 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001666 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667 }
1668
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001669 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001670 rp = kmalloc(rp_len, GFP_ATOMIC);
1671 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001672 err = -ENOMEM;
1673 goto unlock;
1674 }
1675
Johan Hedberg2784eb42011-01-21 13:56:35 +02001676 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001677 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001678 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1679 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001680 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001681 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001682 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001683 continue;
1684 i++;
1685 }
1686
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001687 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001688
Johan Hedberg4c659c32011-11-07 23:13:39 +02001689 /* Recalculate length in case of filtered SCO connections, etc */
1690 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001691
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001692 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001693 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001694
Johan Hedberga38528f2011-01-22 06:46:43 +02001695 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001696
1697unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001698 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001699 return err;
1700}
1701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001702static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001703 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001704{
1705 struct pending_cmd *cmd;
1706 int err;
1707
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001708 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001709 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001710 if (!cmd)
1711 return -ENOMEM;
1712
Johan Hedbergd8457692012-02-17 14:24:57 +02001713 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001715 if (err < 0)
1716 mgmt_pending_remove(cmd);
1717
1718 return err;
1719}
1720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001721static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001723{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001724 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001725 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001726 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001727 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001728 int err;
1729
1730 BT_DBG("");
1731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001732 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001733
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001734 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001736 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737 goto failed;
1738 }
1739
Johan Hedbergd8457692012-02-17 14:24:57 +02001740 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001741 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001742 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001743 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001744 goto failed;
1745 }
1746
1747 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001748 struct mgmt_cp_pin_code_neg_reply ncp;
1749
1750 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001751
1752 BT_ERR("PIN code is not 16 bytes long");
1753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001754 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001755 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001756 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001757 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001758
1759 goto failed;
1760 }
1761
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001762 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001763 if (!cmd) {
1764 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001765 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001766 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001767
Johan Hedbergd8457692012-02-17 14:24:57 +02001768 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001769 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001770 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771
1772 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1773 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001774 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001775
1776failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001777 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778 return err;
1779}
1780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001781static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001782 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001783{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001784 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785 int err;
1786
1787 BT_DBG("");
1788
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001789 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001790
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001791 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001792 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001793 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001794 goto failed;
1795 }
1796
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001797 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798
1799failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001800 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001801 return err;
1802}
1803
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001804static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1805 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001806{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001807 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001808
1809 BT_DBG("");
1810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001812
1813 hdev->io_capability = cp->io_capability;
1814
1815 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001816 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001818 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001820 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1821 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001822}
1823
Gustavo Padovan6039aa732012-05-23 04:04:18 -03001824static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001825{
1826 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001827 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001828
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001829 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001830 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1831 continue;
1832
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833 if (cmd->user_data != conn)
1834 continue;
1835
1836 return cmd;
1837 }
1838
1839 return NULL;
1840}
1841
1842static void pairing_complete(struct pending_cmd *cmd, u8 status)
1843{
1844 struct mgmt_rp_pair_device rp;
1845 struct hci_conn *conn = cmd->user_data;
1846
Johan Hedbergba4e5642011-11-11 00:07:34 +02001847 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001848 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001849
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001850 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001851 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001852
1853 /* So we don't get further callbacks for this connection */
1854 conn->connect_cfm_cb = NULL;
1855 conn->security_cfm_cb = NULL;
1856 conn->disconn_cfm_cb = NULL;
1857
1858 hci_conn_put(conn);
1859
Johan Hedberga664b5b2011-02-19 12:06:02 -03001860 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001861}
1862
1863static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1864{
1865 struct pending_cmd *cmd;
1866
1867 BT_DBG("status %u", status);
1868
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001869 cmd = find_pairing(conn);
1870 if (!cmd)
1871 BT_DBG("Unable to find a pending command");
1872 else
Johan Hedberge2113262012-02-18 15:20:03 +02001873 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874}
1875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001876static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001877 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001878{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001879 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001880 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001881 struct pending_cmd *cmd;
1882 u8 sec_level, auth_type;
1883 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001884 int err;
1885
1886 BT_DBG("");
1887
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001888 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001890 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001891 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001892 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001893 goto unlock;
1894 }
1895
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001896 sec_level = BT_SECURITY_MEDIUM;
1897 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001899 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001901
Andre Guedes591f47f2012-04-24 21:02:49 -03001902 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001903 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1904 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001905 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001906 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1907 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001908
Johan Hedberg1425acb2011-11-11 00:07:35 +02001909 memset(&rp, 0, sizeof(rp));
1910 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1911 rp.addr.type = cp->addr.type;
1912
Ville Tervo30e76272011-02-22 16:10:53 -03001913 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001914 int status;
1915
1916 if (PTR_ERR(conn) == -EBUSY)
1917 status = MGMT_STATUS_BUSY;
1918 else
1919 status = MGMT_STATUS_CONNECT_FAILED;
1920
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001921 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001922 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001923 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001924 goto unlock;
1925 }
1926
1927 if (conn->connect_cfm_cb) {
1928 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001929 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001930 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001931 goto unlock;
1932 }
1933
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001934 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001935 if (!cmd) {
1936 err = -ENOMEM;
1937 hci_conn_put(conn);
1938 goto unlock;
1939 }
1940
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001941 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001942 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001943 conn->connect_cfm_cb = pairing_complete_cb;
1944
Johan Hedberge9a416b2011-02-19 12:05:56 -03001945 conn->security_cfm_cb = pairing_complete_cb;
1946 conn->disconn_cfm_cb = pairing_complete_cb;
1947 conn->io_capability = cp->io_cap;
1948 cmd->user_data = conn;
1949
1950 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001951 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03001952 pairing_complete(cmd, 0);
1953
1954 err = 0;
1955
1956unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001957 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001958 return err;
1959}
1960
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001961static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1962 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001963{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001964 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001965 struct pending_cmd *cmd;
1966 struct hci_conn *conn;
1967 int err;
1968
1969 BT_DBG("");
1970
Johan Hedberg28424702012-02-02 04:02:29 +02001971 hci_dev_lock(hdev);
1972
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001973 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001974 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001975 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001976 goto unlock;
1977 }
1978
Johan Hedberg28424702012-02-02 04:02:29 +02001979 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1980 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001981 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001982 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001983 goto unlock;
1984 }
1985
1986 conn = cmd->user_data;
1987
1988 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001990 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001991 goto unlock;
1992 }
1993
1994 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1995
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001996 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001997 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001998unlock:
1999 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002000 return err;
2001}
2002
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002003static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002004 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2005 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002006{
Johan Hedberga5c29682011-02-19 12:05:57 -03002007 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002008 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002009 int err;
2010
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002011 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002012
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002013 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002016 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002017 }
2018
Andre Guedes591f47f2012-04-24 21:02:49 -03002019 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002020 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2021 else
Brian Gix47c15e22011-11-16 13:53:14 -08002022 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002023
Johan Hedberg272d90d2012-02-09 15:26:12 +02002024 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002025 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002026 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002027 goto done;
2028 }
2029
Andre Guedes591f47f2012-04-24 21:02:49 -03002030 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002031 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002032 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002033
Brian Gix5fe57d92011-12-21 16:12:13 -08002034 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002035 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002036 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002037 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002038 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002039 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002040
Brian Gix47c15e22011-11-16 13:53:14 -08002041 goto done;
2042 }
2043
Brian Gix0df4c182011-11-16 13:53:13 -08002044 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002045 if (!cmd) {
2046 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002047 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002048 }
2049
Brian Gix0df4c182011-11-16 13:53:13 -08002050 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002051 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2052 struct hci_cp_user_passkey_reply cp;
2053
2054 bacpy(&cp.bdaddr, bdaddr);
2055 cp.passkey = passkey;
2056 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2057 } else
2058 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2059
Johan Hedberga664b5b2011-02-19 12:06:02 -03002060 if (err < 0)
2061 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002062
Brian Gix0df4c182011-11-16 13:53:13 -08002063done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002064 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002065 return err;
2066}
2067
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002068static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2069 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002070{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002071 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002072
2073 BT_DBG("");
2074
2075 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002076 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002077 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002078
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002079 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002080 MGMT_OP_USER_CONFIRM_REPLY,
2081 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002082}
2083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002084static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002085 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002086{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002087 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002088
2089 BT_DBG("");
2090
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002091 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002092 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2093 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002094}
2095
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002096static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2097 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002098{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002099 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002100
2101 BT_DBG("");
2102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002103 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002104 MGMT_OP_USER_PASSKEY_REPLY,
2105 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002106}
2107
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002108static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002109 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002110{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002111 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002112
2113 BT_DBG("");
2114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002115 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002116 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2117 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002118}
2119
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002120static int update_name(struct hci_dev *hdev, const char *name)
2121{
2122 struct hci_cp_write_local_name cp;
2123
2124 memcpy(cp.name, name, sizeof(cp.name));
2125
2126 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2127}
2128
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002129static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002130 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002131{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002132 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002133 struct pending_cmd *cmd;
2134 int err;
2135
2136 BT_DBG("");
2137
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002138 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002139
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002140 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002141
Johan Hedbergb5235a62012-02-21 14:32:24 +02002142 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002143 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002144
2145 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002146 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002147 if (err < 0)
2148 goto failed;
2149
2150 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002151 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002152
Johan Hedbergb5235a62012-02-21 14:32:24 +02002153 goto failed;
2154 }
2155
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002156 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002157 if (!cmd) {
2158 err = -ENOMEM;
2159 goto failed;
2160 }
2161
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002162 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002163 if (err < 0)
2164 mgmt_pending_remove(cmd);
2165
2166failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002167 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002168 return err;
2169}
2170
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002171static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002172 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002173{
Szymon Jancc35938b2011-03-22 13:12:21 +01002174 struct pending_cmd *cmd;
2175 int err;
2176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002179 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002180
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002181 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002182 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002183 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184 goto unlock;
2185 }
2186
2187 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002189 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002190 goto unlock;
2191 }
2192
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002193 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002195 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002196 goto unlock;
2197 }
2198
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002199 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002200 if (!cmd) {
2201 err = -ENOMEM;
2202 goto unlock;
2203 }
2204
2205 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2206 if (err < 0)
2207 mgmt_pending_remove(cmd);
2208
2209unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002210 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002211 return err;
2212}
2213
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002214static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002215 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002216{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002217 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002218 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002219 int err;
2220
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002221 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002222
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002223 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002224
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002225 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002226 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002227 MGMT_STATUS_NOT_POWERED, &cp->addr,
2228 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002229 goto unlock;
2230 }
2231
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002232 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002234 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002235 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002236 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002237 status = 0;
2238
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002239 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002240 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002241
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002242unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002243 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002244 return err;
2245}
2246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002247static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002248 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002249{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002250 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002251 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002252 int err;
2253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002254 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002255
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002256 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002257
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002258 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002259 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002260 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2261 MGMT_STATUS_NOT_POWERED, &cp->addr,
2262 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002263 goto unlock;
2264 }
2265
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002266 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002267 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002268 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002269 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002270 status = 0;
2271
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002272 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002273 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002274
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002275unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002276 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002277 return err;
2278}
2279
Andre Guedes5e0452c2012-02-17 20:39:38 -03002280int mgmt_interleaved_discovery(struct hci_dev *hdev)
2281{
2282 int err;
2283
2284 BT_DBG("%s", hdev->name);
2285
2286 hci_dev_lock(hdev);
2287
2288 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2289 if (err < 0)
2290 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2291
2292 hci_dev_unlock(hdev);
2293
2294 return err;
2295}
2296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002297static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002298 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002299{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002300 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002301 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002302 int err;
2303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002304 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002305
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002306 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002307
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002308 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002309 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002310 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002311 goto failed;
2312 }
2313
Andre Guedes642be6c2012-03-21 00:03:37 -03002314 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2315 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2316 MGMT_STATUS_BUSY);
2317 goto failed;
2318 }
2319
Johan Hedbergff9ef572012-01-04 14:23:45 +02002320 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002323 goto failed;
2324 }
2325
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002326 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002327 if (!cmd) {
2328 err = -ENOMEM;
2329 goto failed;
2330 }
2331
Andre Guedes4aab14e2012-02-17 20:39:36 -03002332 hdev->discovery.type = cp->type;
2333
2334 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002335 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002336 if (lmp_bredr_capable(hdev))
2337 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2338 else
2339 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002340 break;
2341
2342 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002343 if (lmp_host_le_capable(hdev))
2344 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002345 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002346 else
2347 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002348 break;
2349
Andre Guedes5e0452c2012-02-17 20:39:38 -03002350 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002351 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2352 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 LE_SCAN_WIN,
2354 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002355 else
2356 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002357 break;
2358
Andre Guedesf39799f2012-02-17 20:39:35 -03002359 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002360 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002361 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002362
Johan Hedberg14a53662011-04-27 10:29:56 -04002363 if (err < 0)
2364 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002365 else
2366 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002367
2368failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002370 return err;
2371}
2372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002373static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002374 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002375{
Johan Hedbergd9306502012-02-20 23:25:18 +02002376 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002377 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002378 struct hci_cp_remote_name_req_cancel cp;
2379 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002380 int err;
2381
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002382 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002384 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002385
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002386 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002387 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002388 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2389 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002390 goto unlock;
2391 }
2392
2393 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002394 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002395 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2396 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002397 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002398 }
2399
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002400 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002401 if (!cmd) {
2402 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002403 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002404 }
2405
Andre Guedese0d9727e2012-03-20 15:15:36 -03002406 switch (hdev->discovery.state) {
2407 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002408 if (test_bit(HCI_INQUIRY, &hdev->flags))
2409 err = hci_cancel_inquiry(hdev);
2410 else
2411 err = hci_cancel_le_scan(hdev);
2412
Andre Guedese0d9727e2012-03-20 15:15:36 -03002413 break;
2414
2415 case DISCOVERY_RESOLVING:
2416 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002417 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002418 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002419 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002420 err = cmd_complete(sk, hdev->id,
2421 MGMT_OP_STOP_DISCOVERY, 0,
2422 &mgmt_cp->type,
2423 sizeof(mgmt_cp->type));
2424 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2425 goto unlock;
2426 }
2427
2428 bacpy(&cp.bdaddr, &e->data.bdaddr);
2429 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2430 sizeof(cp), &cp);
2431
2432 break;
2433
2434 default:
2435 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2436 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002437 }
2438
Johan Hedberg14a53662011-04-27 10:29:56 -04002439 if (err < 0)
2440 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002441 else
2442 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002443
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002444unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002445 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002446 return err;
2447}
2448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002449static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002450 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002451{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002452 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002453 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002454 int err;
2455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002456 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002457
Johan Hedberg561aafb2012-01-04 13:31:59 +02002458 hci_dev_lock(hdev);
2459
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002460 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002462 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002463 goto failed;
2464 }
2465
Johan Hedberga198e7b2012-02-17 14:27:06 +02002466 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002467 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002468 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002469 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002470 goto failed;
2471 }
2472
2473 if (cp->name_known) {
2474 e->name_state = NAME_KNOWN;
2475 list_del(&e->list);
2476 } else {
2477 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002478 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002479 }
2480
2481 err = 0;
2482
2483failed:
2484 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002485 return err;
2486}
2487
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002488static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002489 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002490{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002491 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002492 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002493 int err;
2494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002495 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002496
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002497 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002498
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002499 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002500 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002501 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002502 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002503 status = 0;
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002507
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002508 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002509
2510 return err;
2511}
2512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002513static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002514 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002515{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002516 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002517 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002518 int err;
2519
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002520 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002521
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002522 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002523
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002524 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002525 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002526 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002527 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002528 status = 0;
2529
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002530 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002531 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002532
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002533 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002534
2535 return err;
2536}
2537
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002538static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2539 u16 len)
2540{
2541 struct mgmt_cp_set_device_id *cp = data;
2542 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002543 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002544
2545 BT_DBG("%s", hdev->name);
2546
Szymon Jancc72d4b82012-03-16 16:02:57 +01002547 source = __le16_to_cpu(cp->source);
2548
2549 if (source > 0x0002)
2550 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2551 MGMT_STATUS_INVALID_PARAMS);
2552
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002553 hci_dev_lock(hdev);
2554
Szymon Jancc72d4b82012-03-16 16:02:57 +01002555 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002556 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2557 hdev->devid_product = __le16_to_cpu(cp->product);
2558 hdev->devid_version = __le16_to_cpu(cp->version);
2559
2560 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2561
2562 update_eir(hdev);
2563
2564 hci_dev_unlock(hdev);
2565
2566 return err;
2567}
2568
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002569static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002570 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002571{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002572 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002573 struct hci_cp_write_page_scan_activity acp;
2574 u8 type;
2575 int err;
2576
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002577 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002578
Johan Hedberg5400c042012-02-21 16:40:33 +02002579 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002580 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002581 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002582
2583 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002584 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002586
2587 hci_dev_lock(hdev);
2588
Johan Hedbergf7c68692011-12-15 00:47:36 +02002589 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002590 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002591
2592 /* 22.5 msec page scan interval */
2593 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002594 } else {
2595 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002596
2597 /* default 1.28 sec page scan */
2598 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002599 }
2600
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002601 /* default 11.25 msec page scan window */
2602 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002603
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002604 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2605 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002606 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002607 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002608 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002609 goto done;
2610 }
2611
2612 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2613 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002614 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002615 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002616 goto done;
2617 }
2618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002619 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002620 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002621done:
2622 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002623 return err;
2624}
2625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002627 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002628{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002629 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2630 u16 key_count, expected_len;
2631 int i;
2632
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002633 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002634
2635 expected_len = sizeof(*cp) + key_count *
2636 sizeof(struct mgmt_ltk_info);
2637 if (expected_len != len) {
2638 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002639 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002640 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002641 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002642 }
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002645
2646 hci_dev_lock(hdev);
2647
2648 hci_smp_ltks_clear(hdev);
2649
2650 for (i = 0; i < key_count; i++) {
2651 struct mgmt_ltk_info *key = &cp->keys[i];
2652 u8 type;
2653
2654 if (key->master)
2655 type = HCI_SMP_LTK;
2656 else
2657 type = HCI_SMP_LTK_SLAVE;
2658
Hemant Gupta4596fde2012-04-16 14:57:40 +05302659 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002660 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 type, 0, key->authenticated, key->val,
2662 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002663 }
2664
2665 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002666
2667 return 0;
2668}
2669
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002670static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002671 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2672 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002673 bool var_len;
2674 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002675} mgmt_handlers[] = {
2676 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002677 { read_version, false, MGMT_READ_VERSION_SIZE },
2678 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2679 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2680 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2681 { set_powered, false, MGMT_SETTING_SIZE },
2682 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2683 { set_connectable, false, MGMT_SETTING_SIZE },
2684 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2685 { set_pairable, false, MGMT_SETTING_SIZE },
2686 { set_link_security, false, MGMT_SETTING_SIZE },
2687 { set_ssp, false, MGMT_SETTING_SIZE },
2688 { set_hs, false, MGMT_SETTING_SIZE },
2689 { set_le, false, MGMT_SETTING_SIZE },
2690 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2691 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2692 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2693 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2694 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2695 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2696 { disconnect, false, MGMT_DISCONNECT_SIZE },
2697 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2698 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2699 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2700 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2701 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2702 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2703 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2704 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2705 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2706 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2707 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2708 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2709 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2710 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2711 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2712 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2713 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2714 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2715 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002716 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002717};
2718
2719
Johan Hedberg03811012010-12-08 00:21:06 +02002720int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2721{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002722 void *buf;
2723 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002724 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002725 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002726 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002727 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002728 int err;
2729
2730 BT_DBG("got %zu bytes", msglen);
2731
2732 if (msglen < sizeof(*hdr))
2733 return -EINVAL;
2734
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002735 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002736 if (!buf)
2737 return -ENOMEM;
2738
2739 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2740 err = -EFAULT;
2741 goto done;
2742 }
2743
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002744 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002745 opcode = __le16_to_cpu(hdr->opcode);
2746 index = __le16_to_cpu(hdr->index);
2747 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002748
2749 if (len != msglen - sizeof(*hdr)) {
2750 err = -EINVAL;
2751 goto done;
2752 }
2753
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002754 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002755 hdev = hci_dev_get(index);
2756 if (!hdev) {
2757 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002758 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002759 goto done;
2760 }
2761 }
2762
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002763 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002764 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002765 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002766 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002767 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002768 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002769 }
2770
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002771 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002772 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002773 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002774 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002775 goto done;
2776 }
2777
Johan Hedbergbe22b542012-03-01 22:24:41 +02002778 handler = &mgmt_handlers[opcode];
2779
2780 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002781 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002782 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002783 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002784 goto done;
2785 }
2786
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002787 if (hdev)
2788 mgmt_init_hdev(sk, hdev);
2789
2790 cp = buf + sizeof(*hdr);
2791
Johan Hedbergbe22b542012-03-01 22:24:41 +02002792 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002793 if (err < 0)
2794 goto done;
2795
Johan Hedberg03811012010-12-08 00:21:06 +02002796 err = msglen;
2797
2798done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002799 if (hdev)
2800 hci_dev_put(hdev);
2801
Johan Hedberg03811012010-12-08 00:21:06 +02002802 kfree(buf);
2803 return err;
2804}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002805
Johan Hedbergb24752f2011-11-03 14:40:33 +02002806static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2807{
2808 u8 *status = data;
2809
2810 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2811 mgmt_pending_remove(cmd);
2812}
2813
Johan Hedberg744cf192011-11-08 20:40:14 +02002814int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002815{
Johan Hedberg744cf192011-11-08 20:40:14 +02002816 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002817}
2818
Johan Hedberg744cf192011-11-08 20:40:14 +02002819int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002820{
Johan Hedberg5f159032012-03-02 03:13:19 +02002821 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002822
Johan Hedberg744cf192011-11-08 20:40:14 +02002823 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002824
Johan Hedberg744cf192011-11-08 20:40:14 +02002825 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002826}
2827
Johan Hedberg73f22f62010-12-29 16:00:25 +02002828struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002829 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002830 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002831 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002832};
2833
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002834static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002835{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002836 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002837
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002838 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002839
2840 list_del(&cmd->list);
2841
2842 if (match->sk == NULL) {
2843 match->sk = cmd->sk;
2844 sock_hold(match->sk);
2845 }
2846
2847 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002848}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002849
Johan Hedberg744cf192011-11-08 20:40:14 +02002850int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002851{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002852 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002853 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002854
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002855 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2856 return 0;
2857
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002858 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002859
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002860 if (powered) {
2861 u8 scan = 0;
2862
2863 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2864 scan |= SCAN_PAGE;
2865 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2866 scan |= SCAN_INQUIRY;
2867
2868 if (scan)
2869 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002870
2871 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002872 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002873 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002874 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002875 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002876 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002877 }
2878
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002879 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002880
2881 if (match.sk)
2882 sock_put(match.sk);
2883
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002884 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002885}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002886
Johan Hedberg744cf192011-11-08 20:40:14 +02002887int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002888{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002889 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002890 bool changed = false;
2891 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002892
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002893 if (discoverable) {
2894 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2895 changed = true;
2896 } else {
2897 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2898 changed = true;
2899 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002900
Johan Hedberged9b5f22012-02-21 20:47:06 +02002901 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002902 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002903
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002904 if (changed)
2905 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002906
Johan Hedberg73f22f62010-12-29 16:00:25 +02002907 if (match.sk)
2908 sock_put(match.sk);
2909
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002910 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002911}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002912
Johan Hedberg744cf192011-11-08 20:40:14 +02002913int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002914{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002915 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002916 bool changed = false;
2917 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002918
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002919 if (connectable) {
2920 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2921 changed = true;
2922 } else {
2923 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2924 changed = true;
2925 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002926
Johan Hedberged9b5f22012-02-21 20:47:06 +02002927 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002928 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002929
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002930 if (changed)
2931 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002932
2933 if (match.sk)
2934 sock_put(match.sk);
2935
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002936 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002937}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002938
Johan Hedberg744cf192011-11-08 20:40:14 +02002939int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002940{
Johan Hedbergca69b792011-11-11 18:10:00 +02002941 u8 mgmt_err = mgmt_status(status);
2942
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002943 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002944 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002945 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002946
2947 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002948 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002949 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002950
2951 return 0;
2952}
2953
Cristian Chilipirea53168e52012-05-09 08:44:52 +03002954int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2955 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002956{
Johan Hedberg86742e12011-11-07 23:13:38 +02002957 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002958
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002959 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002960
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002961 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002962 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03002963 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002964 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03002965 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002966 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002967
Johan Hedberg744cf192011-11-08 20:40:14 +02002968 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002969}
Johan Hedbergf7520542011-01-20 12:34:39 +02002970
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002971int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2972{
2973 struct mgmt_ev_new_long_term_key ev;
2974
2975 memset(&ev, 0, sizeof(ev));
2976
2977 ev.store_hint = persistent;
2978 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03002979 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002980 ev.key.authenticated = key->authenticated;
2981 ev.key.enc_size = key->enc_size;
2982 ev.key.ediv = key->ediv;
2983
2984 if (key->type == HCI_SMP_LTK)
2985 ev.key.master = 1;
2986
2987 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2988 memcpy(ev.key.val, key->val, sizeof(key->val));
2989
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002990 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2991 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002992}
2993
Johan Hedbergafc747a2012-01-15 18:11:07 +02002994int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002995 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2996 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002997{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002998 char buf[512];
2999 struct mgmt_ev_device_connected *ev = (void *) buf;
3000 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003001
Johan Hedbergb644ba32012-01-17 21:48:47 +02003002 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003003 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003004
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003005 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003006
Johan Hedbergb644ba32012-01-17 21:48:47 +02003007 if (name_len > 0)
3008 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003009 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003010
3011 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003012 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003014
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003015 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003016
3017 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003018 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003019}
3020
Johan Hedberg8962ee72011-01-20 12:40:27 +02003021static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3022{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003023 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003024 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003025 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003026
Johan Hedberg88c3df12012-02-09 14:27:38 +02003027 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3028 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003029
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003030 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003031 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003032
3033 *sk = cmd->sk;
3034 sock_hold(*sk);
3035
Johan Hedberga664b5b2011-02-19 12:06:02 -03003036 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003037}
3038
Johan Hedberg124f6e32012-02-09 13:50:12 +02003039static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003040{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003041 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003042 struct mgmt_cp_unpair_device *cp = cmd->param;
3043 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003044
3045 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003046 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3047 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003048
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003049 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3050
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003051 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003052
3053 mgmt_pending_remove(cmd);
3054}
3055
Johan Hedbergafc747a2012-01-15 18:11:07 +02003056int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003057 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003058{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003059 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003060 struct sock *sk = NULL;
3061 int err;
3062
Johan Hedberg744cf192011-11-08 20:40:14 +02003063 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003064
Johan Hedbergf7520542011-01-20 12:34:39 +02003065 bacpy(&ev.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003066 ev.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003067
Johan Hedbergafc747a2012-01-15 18:11:07 +02003068 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003069 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003070
3071 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003072 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003073
Johan Hedberg124f6e32012-02-09 13:50:12 +02003074 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003075 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003076
Johan Hedberg8962ee72011-01-20 12:40:27 +02003077 return err;
3078}
3079
Johan Hedberg88c3df12012-02-09 14:27:38 +02003080int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003081 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003082{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003083 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003084 struct pending_cmd *cmd;
3085 int err;
3086
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003087 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003088 if (!cmd)
3089 return -ENOENT;
3090
Johan Hedberg88c3df12012-02-09 14:27:38 +02003091 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003092 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003093
Johan Hedberg88c3df12012-02-09 14:27:38 +02003094 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003095 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003096
Johan Hedberga664b5b2011-02-19 12:06:02 -03003097 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003098
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003099 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003100 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003101 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003102}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003103
Johan Hedberg48264f02011-11-09 13:58:58 +02003104int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003106{
3107 struct mgmt_ev_connect_failed ev;
3108
Johan Hedberg4c659c32011-11-07 23:13:39 +02003109 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003110 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003111 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003112
Johan Hedberg744cf192011-11-08 20:40:14 +02003113 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003114}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003115
Johan Hedberg744cf192011-11-08 20:40:14 +02003116int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003117{
3118 struct mgmt_ev_pin_code_request ev;
3119
Johan Hedbergd8457692012-02-17 14:24:57 +02003120 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003121 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003122 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003123
Johan Hedberg744cf192011-11-08 20:40:14 +02003124 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003125 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003126}
3127
Johan Hedberg744cf192011-11-08 20:40:14 +02003128int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003129 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003130{
3131 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003132 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003133 int err;
3134
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003135 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003136 if (!cmd)
3137 return -ENOENT;
3138
Johan Hedbergd8457692012-02-17 14:24:57 +02003139 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003140 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003141
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003142 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003143 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003144
Johan Hedberga664b5b2011-02-19 12:06:02 -03003145 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003146
3147 return err;
3148}
3149
Johan Hedberg744cf192011-11-08 20:40:14 +02003150int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003151 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003152{
3153 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003154 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003155 int err;
3156
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003157 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003158 if (!cmd)
3159 return -ENOENT;
3160
Johan Hedbergd8457692012-02-17 14:24:57 +02003161 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003162 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003163
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003164 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003166
Johan Hedberga664b5b2011-02-19 12:06:02 -03003167 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003168
3169 return err;
3170}
Johan Hedberga5c29682011-02-19 12:05:57 -03003171
Johan Hedberg744cf192011-11-08 20:40:14 +02003172int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003173 u8 link_type, u8 addr_type, __le32 value,
3174 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003175{
3176 struct mgmt_ev_user_confirm_request ev;
3177
Johan Hedberg744cf192011-11-08 20:40:14 +02003178 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003179
Johan Hedberg272d90d2012-02-09 15:26:12 +02003180 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003181 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003182 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003183 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003184
Johan Hedberg744cf192011-11-08 20:40:14 +02003185 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003186 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003187}
3188
Johan Hedberg272d90d2012-02-09 15:26:12 +02003189int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003190 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003191{
3192 struct mgmt_ev_user_passkey_request ev;
3193
3194 BT_DBG("%s", hdev->name);
3195
Johan Hedberg272d90d2012-02-09 15:26:12 +02003196 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003197 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003198
3199 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003200 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003201}
3202
Brian Gix0df4c182011-11-16 13:53:13 -08003203static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003204 u8 link_type, u8 addr_type, u8 status,
3205 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003206{
3207 struct pending_cmd *cmd;
3208 struct mgmt_rp_user_confirm_reply rp;
3209 int err;
3210
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003211 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003212 if (!cmd)
3213 return -ENOENT;
3214
Johan Hedberg272d90d2012-02-09 15:26:12 +02003215 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003216 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003217 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003218 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003219
Johan Hedberga664b5b2011-02-19 12:06:02 -03003220 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003221
3222 return err;
3223}
3224
Johan Hedberg744cf192011-11-08 20:40:14 +02003225int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003226 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003227{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003228 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003229 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003230}
3231
Johan Hedberg272d90d2012-02-09 15:26:12 +02003232int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003233 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003234{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003235 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003236 status,
3237 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003238}
Johan Hedberg2a611692011-02-19 12:06:00 -03003239
Brian Gix604086b2011-11-23 08:28:33 -08003240int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003241 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003242{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003243 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003244 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003245}
3246
Johan Hedberg272d90d2012-02-09 15:26:12 +02003247int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003248 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003249{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003250 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003251 status,
3252 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003253}
3254
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003255int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003256 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003257{
3258 struct mgmt_ev_auth_failed ev;
3259
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003260 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003261 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003262 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003263
Johan Hedberg744cf192011-11-08 20:40:14 +02003264 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003265}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003266
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003267int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3268{
3269 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003270 bool changed = false;
3271 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003272
3273 if (status) {
3274 u8 mgmt_err = mgmt_status(status);
3275 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003276 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003277 return 0;
3278 }
3279
Johan Hedberg47990ea2012-02-22 11:58:37 +02003280 if (test_bit(HCI_AUTH, &hdev->flags)) {
3281 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3282 changed = true;
3283 } else {
3284 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3285 changed = true;
3286 }
3287
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003288 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003289 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003290
Johan Hedberg47990ea2012-02-22 11:58:37 +02003291 if (changed)
3292 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003293
3294 if (match.sk)
3295 sock_put(match.sk);
3296
3297 return err;
3298}
3299
Johan Hedbergcacaf522012-02-21 00:52:42 +02003300static int clear_eir(struct hci_dev *hdev)
3301{
3302 struct hci_cp_write_eir cp;
3303
3304 if (!(hdev->features[6] & LMP_EXT_INQ))
3305 return 0;
3306
Johan Hedbergc80da272012-02-22 15:38:48 +02003307 memset(hdev->eir, 0, sizeof(hdev->eir));
3308
Johan Hedbergcacaf522012-02-21 00:52:42 +02003309 memset(&cp, 0, sizeof(cp));
3310
3311 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3312}
3313
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003314int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003315{
3316 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003317 bool changed = false;
3318 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003319
3320 if (status) {
3321 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003322
3323 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003324 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003325 err = new_settings(hdev, NULL);
3326
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003327 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3328 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003329
3330 return err;
3331 }
3332
3333 if (enable) {
3334 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3335 changed = true;
3336 } else {
3337 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3338 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003339 }
3340
3341 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3342
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003343 if (changed)
3344 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003345
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003346 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003347 sock_put(match.sk);
3348
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003349 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3350 update_eir(hdev);
3351 else
3352 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003353
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003354 return err;
3355}
3356
Johan Hedberg90e70452012-02-23 23:09:40 +02003357static void class_rsp(struct pending_cmd *cmd, void *data)
3358{
3359 struct cmd_lookup *match = data;
3360
3361 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003362 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003363
3364 list_del(&cmd->list);
3365
3366 if (match->sk == NULL) {
3367 match->sk = cmd->sk;
3368 sock_hold(match->sk);
3369 }
3370
3371 mgmt_pending_free(cmd);
3372}
3373
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003374int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003375 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003376{
Johan Hedberg90e70452012-02-23 23:09:40 +02003377 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3378 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003379
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003380 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3381
Johan Hedberg90e70452012-02-23 23:09:40 +02003382 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3383 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3384 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3385
3386 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003387 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3388 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003389
3390 if (match.sk)
3391 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003392
3393 return err;
3394}
3395
Johan Hedberg744cf192011-11-08 20:40:14 +02003396int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003397{
3398 struct pending_cmd *cmd;
3399 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003400 bool changed = false;
3401 int err = 0;
3402
3403 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3404 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3405 changed = true;
3406 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003407
3408 memset(&ev, 0, sizeof(ev));
3409 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003410 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003411
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003412 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003413 if (!cmd)
3414 goto send_event;
3415
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003416 /* Always assume that either the short or the complete name has
3417 * changed if there was a pending mgmt command */
3418 changed = true;
3419
Johan Hedbergb312b1612011-03-16 14:29:37 +02003420 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003421 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003422 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003423 goto failed;
3424 }
3425
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003426 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003427 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003428 if (err < 0)
3429 goto failed;
3430
3431send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003432 if (changed)
3433 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003434 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003435
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003436 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003437
3438failed:
3439 if (cmd)
3440 mgmt_pending_remove(cmd);
3441 return err;
3442}
Szymon Jancc35938b2011-03-22 13:12:21 +01003443
Johan Hedberg744cf192011-11-08 20:40:14 +02003444int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003445 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003446{
3447 struct pending_cmd *cmd;
3448 int err;
3449
Johan Hedberg744cf192011-11-08 20:40:14 +02003450 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003451
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003452 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003453 if (!cmd)
3454 return -ENOENT;
3455
3456 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003457 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3458 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003459 } else {
3460 struct mgmt_rp_read_local_oob_data rp;
3461
3462 memcpy(rp.hash, hash, sizeof(rp.hash));
3463 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3464
Johan Hedberg744cf192011-11-08 20:40:14 +02003465 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003466 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3467 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003468 }
3469
3470 mgmt_pending_remove(cmd);
3471
3472 return err;
3473}
Johan Hedberge17acd42011-03-30 23:57:16 +03003474
Johan Hedberg06199cf2012-02-22 16:37:11 +02003475int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3476{
3477 struct cmd_lookup match = { NULL, hdev };
3478 bool changed = false;
3479 int err = 0;
3480
3481 if (status) {
3482 u8 mgmt_err = mgmt_status(status);
3483
3484 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003485 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003486 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003487
Szymon Jancd97dcb62012-03-16 16:02:56 +01003488 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3489 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003490
3491 return err;
3492 }
3493
3494 if (enable) {
3495 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3496 changed = true;
3497 } else {
3498 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3499 changed = true;
3500 }
3501
3502 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3503
3504 if (changed)
3505 err = new_settings(hdev, match.sk);
3506
3507 if (match.sk)
3508 sock_put(match.sk);
3509
3510 return err;
3511}
3512
Johan Hedberg48264f02011-11-09 13:58:58 +02003513int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003514 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3515 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003516{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003517 char buf[512];
3518 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003519 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003520
Johan Hedberg1dc06092012-01-15 21:01:23 +02003521 /* Leave 5 bytes for a potential CoD field */
3522 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003523 return -EINVAL;
3524
Johan Hedberg1dc06092012-01-15 21:01:23 +02003525 memset(buf, 0, sizeof(buf));
3526
Johan Hedberge319d2e2012-01-15 19:51:59 +02003527 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003528 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003529 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003530 if (cfm_name)
3531 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003532 if (!ssp)
3533 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003534
Johan Hedberg1dc06092012-01-15 21:01:23 +02003535 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003536 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003537
Johan Hedberg1dc06092012-01-15 21:01:23 +02003538 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3539 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003540 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003541
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003542 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003543
3544 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003545
Johan Hedberge319d2e2012-01-15 19:51:59 +02003546 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003547}
Johan Hedberga88a9652011-03-30 13:18:12 +03003548
Johan Hedbergb644ba32012-01-17 21:48:47 +02003549int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003550 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003551{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003552 struct mgmt_ev_device_found *ev;
3553 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3554 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003555
Johan Hedbergb644ba32012-01-17 21:48:47 +02003556 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003557
Johan Hedbergb644ba32012-01-17 21:48:47 +02003558 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003559
Johan Hedbergb644ba32012-01-17 21:48:47 +02003560 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003561 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003562 ev->rssi = rssi;
3563
3564 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003565 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003566
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003567 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003568
Johan Hedberg053c7e02012-02-04 00:06:00 +02003569 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003570 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003571}
Johan Hedberg314b2382011-04-27 10:29:57 -04003572
Andre Guedes7a135102011-11-09 17:14:25 -03003573int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003574{
3575 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003576 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003577 int err;
3578
Andre Guedes203159d2012-02-13 15:41:01 -03003579 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3580
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003581 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003582 if (!cmd)
3583 return -ENOENT;
3584
Johan Hedbergf808e162012-02-19 12:52:07 +02003585 type = hdev->discovery.type;
3586
3587 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003588 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003589 mgmt_pending_remove(cmd);
3590
3591 return err;
3592}
3593
Andre Guedese6d465c2011-11-09 17:14:26 -03003594int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3595{
3596 struct pending_cmd *cmd;
3597 int err;
3598
3599 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3600 if (!cmd)
3601 return -ENOENT;
3602
Johan Hedbergd9306502012-02-20 23:25:18 +02003603 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003604 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003605 mgmt_pending_remove(cmd);
3606
3607 return err;
3608}
Johan Hedberg314b2382011-04-27 10:29:57 -04003609
Johan Hedberg744cf192011-11-08 20:40:14 +02003610int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003611{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003612 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003613 struct pending_cmd *cmd;
3614
Andre Guedes343fb142011-11-22 17:14:19 -03003615 BT_DBG("%s discovering %u", hdev->name, discovering);
3616
Johan Hedberg164a6e72011-11-01 17:06:44 +02003617 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003618 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003619 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003620 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003621
3622 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003623 u8 type = hdev->discovery.type;
3624
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003625 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3626 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003627 mgmt_pending_remove(cmd);
3628 }
3629
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003630 memset(&ev, 0, sizeof(ev));
3631 ev.type = hdev->discovery.type;
3632 ev.discovering = discovering;
3633
3634 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003635}
Antti Julku5e762442011-08-25 16:48:02 +03003636
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003637int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003638{
3639 struct pending_cmd *cmd;
3640 struct mgmt_ev_device_blocked ev;
3641
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003642 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003643
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003644 bacpy(&ev.addr.bdaddr, bdaddr);
3645 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003646
Johan Hedberg744cf192011-11-08 20:40:14 +02003647 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003648 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003649}
3650
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003651int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003652{
3653 struct pending_cmd *cmd;
3654 struct mgmt_ev_device_unblocked ev;
3655
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003656 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003657
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003658 bacpy(&ev.addr.bdaddr, bdaddr);
3659 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003660
Johan Hedberg744cf192011-11-08 20:40:14 +02003661 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003662 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003663}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003664
3665module_param(enable_hs, bool, 0644);
3666MODULE_PARM_DESC(enable_hs, "Enable High Speed support");