blob: ad6613d17ca6de815be200b9576d6ecf510fef0d [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
Andre Guedes790eff42012-06-07 19:05:46 -0300213 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214 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
Andre Guedes790eff42012-06-07 19:05:46 -0300244 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
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
Andre Guedes12b94562012-06-07 19:05:45 -0300690 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200691 if (!cmd)
692 return NULL;
693
694 cmd->opcode = opcode;
695 cmd->index = hdev->id;
696
Andre Guedes12b94562012-06-07 19:05:45 -0300697 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200698 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
Andre Guedes790eff42012-06-07 19:05:46 -0300815 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200816 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
Andre Guedes92c4c202012-06-07 19:05:44 -03001271 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272 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
Vishal Agarwalf9607272012-06-13 05:32:43 +05301601 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
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);
Andre Guedes3701f942012-06-11 18:41:12 -03001614 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615
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));
Andre Guedes92c4c202012-06-07 19:05:44 -03001670 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001671 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
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001781static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1782 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001783{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001784 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001785
1786 BT_DBG("");
1787
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001788 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001789
1790 hdev->io_capability = cp->io_capability;
1791
1792 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001793 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001794
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001795 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001796
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001797 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1798 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001799}
1800
Gustavo Padovan6039aa732012-05-23 04:04:18 -03001801static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001802{
1803 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001804 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001805
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001806 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001807 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1808 continue;
1809
Johan Hedberge9a416b2011-02-19 12:05:56 -03001810 if (cmd->user_data != conn)
1811 continue;
1812
1813 return cmd;
1814 }
1815
1816 return NULL;
1817}
1818
1819static void pairing_complete(struct pending_cmd *cmd, u8 status)
1820{
1821 struct mgmt_rp_pair_device rp;
1822 struct hci_conn *conn = cmd->user_data;
1823
Johan Hedbergba4e5642011-11-11 00:07:34 +02001824 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001825 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001826
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001827 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001828 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001829
1830 /* So we don't get further callbacks for this connection */
1831 conn->connect_cfm_cb = NULL;
1832 conn->security_cfm_cb = NULL;
1833 conn->disconn_cfm_cb = NULL;
1834
1835 hci_conn_put(conn);
1836
Johan Hedberga664b5b2011-02-19 12:06:02 -03001837 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001838}
1839
1840static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1841{
1842 struct pending_cmd *cmd;
1843
1844 BT_DBG("status %u", status);
1845
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001846 cmd = find_pairing(conn);
1847 if (!cmd)
1848 BT_DBG("Unable to find a pending command");
1849 else
Johan Hedberge2113262012-02-18 15:20:03 +02001850 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001851}
1852
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301853static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1854{
1855 struct pending_cmd *cmd;
1856
1857 BT_DBG("status %u", status);
1858
1859 if (!status)
1860 return;
1861
1862 cmd = find_pairing(conn);
1863 if (!cmd)
1864 BT_DBG("Unable to find a pending command");
1865 else
1866 pairing_complete(cmd, mgmt_status(status));
1867}
1868
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001869static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001870 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001871{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001872 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001873 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874 struct pending_cmd *cmd;
1875 u8 sec_level, auth_type;
1876 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001877 int err;
1878
1879 BT_DBG("");
1880
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001881 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001882
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001883 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001884 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001885 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001886 goto unlock;
1887 }
1888
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001889 sec_level = BT_SECURITY_MEDIUM;
1890 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001892 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001893 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894
Andre Guedes591f47f2012-04-24 21:02:49 -03001895 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001896 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1897 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001898 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001899 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1900 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001901
Johan Hedberg1425acb2011-11-11 00:07:35 +02001902 memset(&rp, 0, sizeof(rp));
1903 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1904 rp.addr.type = cp->addr.type;
1905
Ville Tervo30e76272011-02-22 16:10:53 -03001906 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001907 int status;
1908
1909 if (PTR_ERR(conn) == -EBUSY)
1910 status = MGMT_STATUS_BUSY;
1911 else
1912 status = MGMT_STATUS_CONNECT_FAILED;
1913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001915 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001916 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001917 goto unlock;
1918 }
1919
1920 if (conn->connect_cfm_cb) {
1921 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001922 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001923 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001924 goto unlock;
1925 }
1926
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001927 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001928 if (!cmd) {
1929 err = -ENOMEM;
1930 hci_conn_put(conn);
1931 goto unlock;
1932 }
1933
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001934 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001935 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001936 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301937 else
1938 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001939
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940 conn->security_cfm_cb = pairing_complete_cb;
1941 conn->disconn_cfm_cb = pairing_complete_cb;
1942 conn->io_capability = cp->io_cap;
1943 cmd->user_data = conn;
1944
1945 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001946 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03001947 pairing_complete(cmd, 0);
1948
1949 err = 0;
1950
1951unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001952 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001953 return err;
1954}
1955
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001956static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1957 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001958{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001959 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001960 struct pending_cmd *cmd;
1961 struct hci_conn *conn;
1962 int err;
1963
1964 BT_DBG("");
1965
Johan Hedberg28424702012-02-02 04:02:29 +02001966 hci_dev_lock(hdev);
1967
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001968 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001969 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001970 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001971 goto unlock;
1972 }
1973
Johan Hedberg28424702012-02-02 04:02:29 +02001974 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1975 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001976 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001977 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001978 goto unlock;
1979 }
1980
1981 conn = cmd->user_data;
1982
1983 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001985 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001986 goto unlock;
1987 }
1988
1989 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1990
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001991 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001992 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001993unlock:
1994 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02001995 return err;
1996}
1997
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001998static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001999 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2000 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002001{
Johan Hedberga5c29682011-02-19 12:05:57 -03002002 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002003 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002004 int err;
2005
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002006 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002007
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002008 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002009 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002011 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002012 }
2013
Andre Guedes591f47f2012-04-24 21:02:49 -03002014 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002015 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2016 else
Brian Gix47c15e22011-11-16 13:53:14 -08002017 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002018
Johan Hedberg272d90d2012-02-09 15:26:12 +02002019 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002020 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002021 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002022 goto done;
2023 }
2024
Andre Guedes591f47f2012-04-24 21:02:49 -03002025 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002026 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002027 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002028
Brian Gix5fe57d92011-12-21 16:12:13 -08002029 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002030 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002031 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002032 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002033 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002034 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002035
Brian Gix47c15e22011-11-16 13:53:14 -08002036 goto done;
2037 }
2038
Brian Gix0df4c182011-11-16 13:53:13 -08002039 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002040 if (!cmd) {
2041 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002042 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002043 }
2044
Brian Gix0df4c182011-11-16 13:53:13 -08002045 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002046 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2047 struct hci_cp_user_passkey_reply cp;
2048
2049 bacpy(&cp.bdaddr, bdaddr);
2050 cp.passkey = passkey;
2051 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2052 } else
2053 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2054
Johan Hedberga664b5b2011-02-19 12:06:02 -03002055 if (err < 0)
2056 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002057
Brian Gix0df4c182011-11-16 13:53:13 -08002058done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002059 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002060 return err;
2061}
2062
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302063static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2064 void *data, u16 len)
2065{
2066 struct mgmt_cp_pin_code_neg_reply *cp = data;
2067
2068 BT_DBG("");
2069
2070 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2071 MGMT_OP_PIN_CODE_NEG_REPLY,
2072 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2073}
2074
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002075static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2076 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002077{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002078 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002079
2080 BT_DBG("");
2081
2082 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002084 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002086 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002087 MGMT_OP_USER_CONFIRM_REPLY,
2088 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002089}
2090
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002091static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002092 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002093{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002094 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002095
2096 BT_DBG("");
2097
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002099 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2100 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002101}
2102
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002103static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2104 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002105{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002106 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002107
2108 BT_DBG("");
2109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002110 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002111 MGMT_OP_USER_PASSKEY_REPLY,
2112 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002113}
2114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002115static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002116 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002117{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002118 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002119
2120 BT_DBG("");
2121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002122 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002123 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2124 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002125}
2126
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002127static int update_name(struct hci_dev *hdev, const char *name)
2128{
2129 struct hci_cp_write_local_name cp;
2130
2131 memcpy(cp.name, name, sizeof(cp.name));
2132
2133 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2134}
2135
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002136static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002137 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002138{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002139 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002140 struct pending_cmd *cmd;
2141 int err;
2142
2143 BT_DBG("");
2144
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002145 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002146
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002147 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002148
Johan Hedbergb5235a62012-02-21 14:32:24 +02002149 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002150 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002151
2152 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002153 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002154 if (err < 0)
2155 goto failed;
2156
2157 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002158 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002159
Johan Hedbergb5235a62012-02-21 14:32:24 +02002160 goto failed;
2161 }
2162
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002163 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002164 if (!cmd) {
2165 err = -ENOMEM;
2166 goto failed;
2167 }
2168
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002169 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002170 if (err < 0)
2171 mgmt_pending_remove(cmd);
2172
2173failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002175 return err;
2176}
2177
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002178static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002179 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002180{
Szymon Jancc35938b2011-03-22 13:12:21 +01002181 struct pending_cmd *cmd;
2182 int err;
2183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002184 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002185
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002186 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002187
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002188 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002189 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002191 goto unlock;
2192 }
2193
2194 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002195 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002196 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002197 goto unlock;
2198 }
2199
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002200 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002201 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002202 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002203 goto unlock;
2204 }
2205
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002206 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002207 if (!cmd) {
2208 err = -ENOMEM;
2209 goto unlock;
2210 }
2211
2212 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2213 if (err < 0)
2214 mgmt_pending_remove(cmd);
2215
2216unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002217 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002218 return err;
2219}
2220
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002221static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002222 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002223{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002224 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002225 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002226 int err;
2227
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002228 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002229
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002230 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002231
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002232 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002233 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002234 MGMT_STATUS_NOT_POWERED, &cp->addr,
2235 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002236 goto unlock;
2237 }
2238
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002239 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002240 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002241 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002242 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002243 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002244 status = 0;
2245
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002246 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002247 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002248
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002249unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002250 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002251 return err;
2252}
2253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002254static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002255 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002256{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002257 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002258 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002259 int err;
2260
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002261 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002262
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002263 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002264
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002265 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002266 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002267 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2268 MGMT_STATUS_NOT_POWERED, &cp->addr,
2269 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002270 goto unlock;
2271 }
2272
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002273 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002274 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002275 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002276 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002277 status = 0;
2278
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002279 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002280 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002281
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002282unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002283 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002284 return err;
2285}
2286
Andre Guedes5e0452c2012-02-17 20:39:38 -03002287int mgmt_interleaved_discovery(struct hci_dev *hdev)
2288{
2289 int err;
2290
2291 BT_DBG("%s", hdev->name);
2292
2293 hci_dev_lock(hdev);
2294
2295 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2296 if (err < 0)
2297 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2298
2299 hci_dev_unlock(hdev);
2300
2301 return err;
2302}
2303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002304static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002305 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002306{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002307 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002308 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002309 int err;
2310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002311 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002312
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002313 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002314
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002315 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002316 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002317 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002318 goto failed;
2319 }
2320
Andre Guedes642be6c2012-03-21 00:03:37 -03002321 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2322 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2323 MGMT_STATUS_BUSY);
2324 goto failed;
2325 }
2326
Johan Hedbergff9ef572012-01-04 14:23:45 +02002327 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002328 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002329 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002330 goto failed;
2331 }
2332
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002333 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002334 if (!cmd) {
2335 err = -ENOMEM;
2336 goto failed;
2337 }
2338
Andre Guedes4aab14e2012-02-17 20:39:36 -03002339 hdev->discovery.type = cp->type;
2340
2341 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002342 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002343 if (lmp_bredr_capable(hdev))
2344 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2345 else
2346 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002347 break;
2348
2349 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002350 if (lmp_host_le_capable(hdev))
2351 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002352 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002353 else
2354 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002355 break;
2356
Andre Guedes5e0452c2012-02-17 20:39:38 -03002357 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002358 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2359 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002360 LE_SCAN_WIN,
2361 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002362 else
2363 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002364 break;
2365
Andre Guedesf39799f2012-02-17 20:39:35 -03002366 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002367 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002368 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002369
Johan Hedberg14a53662011-04-27 10:29:56 -04002370 if (err < 0)
2371 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002372 else
2373 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002374
2375failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002376 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002377 return err;
2378}
2379
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002380static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002381 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002382{
Johan Hedbergd9306502012-02-20 23:25:18 +02002383 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002384 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002385 struct hci_cp_remote_name_req_cancel cp;
2386 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002387 int err;
2388
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002389 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002390
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002391 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002392
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002393 if (!hci_discovery_active(hdev)) {
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_REJECTED, &mgmt_cp->type,
2396 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002397 goto unlock;
2398 }
2399
2400 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002401 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002402 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2403 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002404 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002405 }
2406
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002407 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002408 if (!cmd) {
2409 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002410 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002411 }
2412
Andre Guedese0d9727e2012-03-20 15:15:36 -03002413 switch (hdev->discovery.state) {
2414 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002415 if (test_bit(HCI_INQUIRY, &hdev->flags))
2416 err = hci_cancel_inquiry(hdev);
2417 else
2418 err = hci_cancel_le_scan(hdev);
2419
Andre Guedese0d9727e2012-03-20 15:15:36 -03002420 break;
2421
2422 case DISCOVERY_RESOLVING:
2423 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002424 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002425 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002426 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002427 err = cmd_complete(sk, hdev->id,
2428 MGMT_OP_STOP_DISCOVERY, 0,
2429 &mgmt_cp->type,
2430 sizeof(mgmt_cp->type));
2431 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2432 goto unlock;
2433 }
2434
2435 bacpy(&cp.bdaddr, &e->data.bdaddr);
2436 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2437 sizeof(cp), &cp);
2438
2439 break;
2440
2441 default:
2442 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2443 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002444 }
2445
Johan Hedberg14a53662011-04-27 10:29:56 -04002446 if (err < 0)
2447 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002448 else
2449 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002450
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002451unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002452 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002453 return err;
2454}
2455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002456static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002457 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002458{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002459 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002460 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002461 int err;
2462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002463 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002464
Johan Hedberg561aafb2012-01-04 13:31:59 +02002465 hci_dev_lock(hdev);
2466
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002467 if (!hci_discovery_active(hdev)) {
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_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002470 goto failed;
2471 }
2472
Johan Hedberga198e7b2012-02-17 14:27:06 +02002473 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002474 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002475 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002476 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002477 goto failed;
2478 }
2479
2480 if (cp->name_known) {
2481 e->name_state = NAME_KNOWN;
2482 list_del(&e->list);
2483 } else {
2484 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002485 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002486 }
2487
2488 err = 0;
2489
2490failed:
2491 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002492 return err;
2493}
2494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002495static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002496 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002497{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002498 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002499 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002500 int err;
2501
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002502 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002503
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002504 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002505
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002506 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002507 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002508 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002509 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002510 status = 0;
2511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002513 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002514
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002515 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002516
2517 return err;
2518}
2519
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002520static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002521 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002522{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002523 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002524 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002525 int err;
2526
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002527 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002528
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002529 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002530
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002531 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002532 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002533 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002534 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002535 status = 0;
2536
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002537 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002538 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002540 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002541
2542 return err;
2543}
2544
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002545static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2546 u16 len)
2547{
2548 struct mgmt_cp_set_device_id *cp = data;
2549 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002550 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002551
2552 BT_DBG("%s", hdev->name);
2553
Szymon Jancc72d4b82012-03-16 16:02:57 +01002554 source = __le16_to_cpu(cp->source);
2555
2556 if (source > 0x0002)
2557 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2558 MGMT_STATUS_INVALID_PARAMS);
2559
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002560 hci_dev_lock(hdev);
2561
Szymon Jancc72d4b82012-03-16 16:02:57 +01002562 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002563 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2564 hdev->devid_product = __le16_to_cpu(cp->product);
2565 hdev->devid_version = __le16_to_cpu(cp->version);
2566
2567 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2568
2569 update_eir(hdev);
2570
2571 hci_dev_unlock(hdev);
2572
2573 return err;
2574}
2575
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002576static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002577 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002578{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002579 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002580 struct hci_cp_write_page_scan_activity acp;
2581 u8 type;
2582 int err;
2583
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002584 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002585
Johan Hedberg5400c042012-02-21 16:40:33 +02002586 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002587 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002589
2590 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002591 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002592 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002593
2594 hci_dev_lock(hdev);
2595
Johan Hedbergf7c68692011-12-15 00:47:36 +02002596 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002597 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002598
Johan Hedberg83ce9a062012-06-28 13:44:30 +03002599 /* 160 msec page scan interval */
2600 acp.interval = __constant_cpu_to_le16(0x0100);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002601 } else {
2602 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002603
2604 /* default 1.28 sec page scan */
2605 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002606 }
2607
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002608 /* default 11.25 msec page scan window */
2609 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002610
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002611 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2612 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002613 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
2619 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2620 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002621 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002622 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002623 goto done;
2624 }
2625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002627 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002628done:
2629 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002630 return err;
2631}
2632
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002633static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002634 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002635{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002636 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2637 u16 key_count, expected_len;
2638 int i;
2639
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002640 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002641
2642 expected_len = sizeof(*cp) + key_count *
2643 sizeof(struct mgmt_ltk_info);
2644 if (expected_len != len) {
2645 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002646 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002647 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002648 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002649 }
2650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002651 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002652
2653 hci_dev_lock(hdev);
2654
2655 hci_smp_ltks_clear(hdev);
2656
2657 for (i = 0; i < key_count; i++) {
2658 struct mgmt_ltk_info *key = &cp->keys[i];
2659 u8 type;
2660
2661 if (key->master)
2662 type = HCI_SMP_LTK;
2663 else
2664 type = HCI_SMP_LTK_SLAVE;
2665
Hemant Gupta4596fde2012-04-16 14:57:40 +05302666 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002667 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002668 type, 0, key->authenticated, key->val,
2669 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002670 }
2671
2672 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002673
2674 return 0;
2675}
2676
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002677static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002678 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2679 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002680 bool var_len;
2681 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002682} mgmt_handlers[] = {
2683 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002684 { read_version, false, MGMT_READ_VERSION_SIZE },
2685 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2686 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2687 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2688 { set_powered, false, MGMT_SETTING_SIZE },
2689 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2690 { set_connectable, false, MGMT_SETTING_SIZE },
2691 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2692 { set_pairable, false, MGMT_SETTING_SIZE },
2693 { set_link_security, false, MGMT_SETTING_SIZE },
2694 { set_ssp, false, MGMT_SETTING_SIZE },
2695 { set_hs, false, MGMT_SETTING_SIZE },
2696 { set_le, false, MGMT_SETTING_SIZE },
2697 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2698 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2699 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2700 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2701 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2702 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2703 { disconnect, false, MGMT_DISCONNECT_SIZE },
2704 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2705 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2706 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2707 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2708 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2709 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2710 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2711 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2712 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2713 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2714 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2715 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2716 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2717 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2718 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2719 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2720 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2721 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2722 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002723 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002724};
2725
2726
Johan Hedberg03811012010-12-08 00:21:06 +02002727int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2728{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002729 void *buf;
2730 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002731 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002732 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002733 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002734 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002735 int err;
2736
2737 BT_DBG("got %zu bytes", msglen);
2738
2739 if (msglen < sizeof(*hdr))
2740 return -EINVAL;
2741
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002742 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002743 if (!buf)
2744 return -ENOMEM;
2745
2746 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2747 err = -EFAULT;
2748 goto done;
2749 }
2750
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002751 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002752 opcode = __le16_to_cpu(hdr->opcode);
2753 index = __le16_to_cpu(hdr->index);
2754 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002755
2756 if (len != msglen - sizeof(*hdr)) {
2757 err = -EINVAL;
2758 goto done;
2759 }
2760
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002761 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002762 hdev = hci_dev_get(index);
2763 if (!hdev) {
2764 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002765 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002766 goto done;
2767 }
2768 }
2769
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002770 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002771 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002772 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002773 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002774 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002775 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002776 }
2777
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002778 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002779 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002780 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002781 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002782 goto done;
2783 }
2784
Johan Hedbergbe22b542012-03-01 22:24:41 +02002785 handler = &mgmt_handlers[opcode];
2786
2787 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002788 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002789 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002790 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002791 goto done;
2792 }
2793
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002794 if (hdev)
2795 mgmt_init_hdev(sk, hdev);
2796
2797 cp = buf + sizeof(*hdr);
2798
Johan Hedbergbe22b542012-03-01 22:24:41 +02002799 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002800 if (err < 0)
2801 goto done;
2802
Johan Hedberg03811012010-12-08 00:21:06 +02002803 err = msglen;
2804
2805done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002806 if (hdev)
2807 hci_dev_put(hdev);
2808
Johan Hedberg03811012010-12-08 00:21:06 +02002809 kfree(buf);
2810 return err;
2811}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002812
Johan Hedbergb24752f2011-11-03 14:40:33 +02002813static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2814{
2815 u8 *status = data;
2816
2817 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2818 mgmt_pending_remove(cmd);
2819}
2820
Johan Hedberg744cf192011-11-08 20:40:14 +02002821int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002822{
Johan Hedberg744cf192011-11-08 20:40:14 +02002823 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002824}
2825
Johan Hedberg744cf192011-11-08 20:40:14 +02002826int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002827{
Johan Hedberg5f159032012-03-02 03:13:19 +02002828 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002829
Johan Hedberg744cf192011-11-08 20:40:14 +02002830 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002831
Johan Hedberg744cf192011-11-08 20:40:14 +02002832 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002833}
2834
Johan Hedberg73f22f62010-12-29 16:00:25 +02002835struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002836 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002837 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002838 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002839};
2840
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002841static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002842{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002843 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002844
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002845 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002846
2847 list_del(&cmd->list);
2848
2849 if (match->sk == NULL) {
2850 match->sk = cmd->sk;
2851 sock_hold(match->sk);
2852 }
2853
2854 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002855}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002856
Johan Hedberg744cf192011-11-08 20:40:14 +02002857int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002858{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002859 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002860 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002861
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002862 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2863 return 0;
2864
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002865 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002866
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002867 if (powered) {
2868 u8 scan = 0;
2869
2870 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2871 scan |= SCAN_PAGE;
2872 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2873 scan |= SCAN_INQUIRY;
2874
2875 if (scan)
2876 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002877
2878 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002879 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002880 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002881 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002882 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002883 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002884 }
2885
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002886 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002887
2888 if (match.sk)
2889 sock_put(match.sk);
2890
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002891 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002892}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002893
Johan Hedberg744cf192011-11-08 20:40:14 +02002894int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002895{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002896 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002897 bool changed = false;
2898 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002899
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002900 if (discoverable) {
2901 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2902 changed = true;
2903 } else {
2904 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2905 changed = true;
2906 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002907
Johan Hedberged9b5f22012-02-21 20:47:06 +02002908 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002909 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002910
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002911 if (changed)
2912 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002913
Johan Hedberg73f22f62010-12-29 16:00:25 +02002914 if (match.sk)
2915 sock_put(match.sk);
2916
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002917 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002918}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002919
Johan Hedberg744cf192011-11-08 20:40:14 +02002920int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002921{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002922 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002923 bool changed = false;
2924 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002925
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002926 if (connectable) {
2927 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2928 changed = true;
2929 } else {
2930 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2931 changed = true;
2932 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002933
Johan Hedberged9b5f22012-02-21 20:47:06 +02002934 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002935 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002936
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002937 if (changed)
2938 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002939
2940 if (match.sk)
2941 sock_put(match.sk);
2942
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002943 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002944}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002945
Johan Hedberg744cf192011-11-08 20:40:14 +02002946int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002947{
Johan Hedbergca69b792011-11-11 18:10:00 +02002948 u8 mgmt_err = mgmt_status(status);
2949
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002950 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002951 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002952 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002953
2954 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002955 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002956 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002957
2958 return 0;
2959}
2960
Cristian Chilipirea53168e52012-05-09 08:44:52 +03002961int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2962 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002963{
Johan Hedberg86742e12011-11-07 23:13:38 +02002964 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002965
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002966 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002967
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002968 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002969 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03002970 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002971 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03002972 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002973 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002974
Johan Hedberg744cf192011-11-08 20:40:14 +02002975 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002976}
Johan Hedbergf7520542011-01-20 12:34:39 +02002977
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002978int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2979{
2980 struct mgmt_ev_new_long_term_key ev;
2981
2982 memset(&ev, 0, sizeof(ev));
2983
2984 ev.store_hint = persistent;
2985 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03002986 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002987 ev.key.authenticated = key->authenticated;
2988 ev.key.enc_size = key->enc_size;
2989 ev.key.ediv = key->ediv;
2990
2991 if (key->type == HCI_SMP_LTK)
2992 ev.key.master = 1;
2993
2994 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2995 memcpy(ev.key.val, key->val, sizeof(key->val));
2996
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002997 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2998 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002999}
3000
Johan Hedbergafc747a2012-01-15 18:11:07 +02003001int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003002 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3003 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003004{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003005 char buf[512];
3006 struct mgmt_ev_device_connected *ev = (void *) buf;
3007 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003008
Johan Hedbergb644ba32012-01-17 21:48:47 +02003009 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003010 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003011
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003012 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003013
Johan Hedbergb644ba32012-01-17 21:48:47 +02003014 if (name_len > 0)
3015 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003016 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003017
3018 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003019 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003020 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003021
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003022 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003023
3024 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003025 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003026}
3027
Johan Hedberg8962ee72011-01-20 12:40:27 +02003028static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3029{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003030 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003031 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003032 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003033
Johan Hedberg88c3df12012-02-09 14:27:38 +02003034 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3035 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003036
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003037 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039
3040 *sk = cmd->sk;
3041 sock_hold(*sk);
3042
Johan Hedberga664b5b2011-02-19 12:06:02 -03003043 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003044}
3045
Johan Hedberg124f6e32012-02-09 13:50:12 +02003046static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003047{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003048 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003049 struct mgmt_cp_unpair_device *cp = cmd->param;
3050 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003051
3052 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003053 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3054 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003055
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003056 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3057
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003058 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003059
3060 mgmt_pending_remove(cmd);
3061}
3062
Johan Hedbergafc747a2012-01-15 18:11:07 +02003063int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003064 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003065{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003066 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003067 struct sock *sk = NULL;
3068 int err;
3069
Johan Hedberg744cf192011-11-08 20:40:14 +02003070 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003071
Johan Hedbergf7520542011-01-20 12:34:39 +02003072 bacpy(&ev.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003073 ev.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003074
Johan Hedbergafc747a2012-01-15 18:11:07 +02003075 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003076 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003077
3078 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003079 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003080
Johan Hedberg124f6e32012-02-09 13:50:12 +02003081 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003082 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003083
Johan Hedberg8962ee72011-01-20 12:40:27 +02003084 return err;
3085}
3086
Johan Hedberg88c3df12012-02-09 14:27:38 +02003087int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003088 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003089{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003090 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003091 struct pending_cmd *cmd;
3092 int err;
3093
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003094 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003095 if (!cmd)
3096 return -ENOENT;
3097
Johan Hedberg88c3df12012-02-09 14:27:38 +02003098 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003099 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003100
Johan Hedberg88c3df12012-02-09 14:27:38 +02003101 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003102 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003103
Johan Hedberga664b5b2011-02-19 12:06:02 -03003104 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003105
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003106 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003107 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003108 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003109}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003110
Johan Hedberg48264f02011-11-09 13:58:58 +02003111int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003112 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003113{
3114 struct mgmt_ev_connect_failed ev;
3115
Johan Hedberg4c659c32011-11-07 23:13:39 +02003116 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003117 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003118 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003119
Johan Hedberg744cf192011-11-08 20:40:14 +02003120 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003121}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003122
Johan Hedberg744cf192011-11-08 20:40:14 +02003123int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003124{
3125 struct mgmt_ev_pin_code_request ev;
3126
Johan Hedbergd8457692012-02-17 14:24:57 +02003127 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003128 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003129 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003130
Johan Hedberg744cf192011-11-08 20:40:14 +02003131 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003133}
3134
Johan Hedberg744cf192011-11-08 20:40:14 +02003135int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003136 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003137{
3138 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003139 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003140 int err;
3141
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003142 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003143 if (!cmd)
3144 return -ENOENT;
3145
Johan Hedbergd8457692012-02-17 14:24:57 +02003146 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003147 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003148
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003149 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003150 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003151
Johan Hedberga664b5b2011-02-19 12:06:02 -03003152 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003153
3154 return err;
3155}
3156
Johan Hedberg744cf192011-11-08 20:40:14 +02003157int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003158 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003159{
3160 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003161 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003162 int err;
3163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003164 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003165 if (!cmd)
3166 return -ENOENT;
3167
Johan Hedbergd8457692012-02-17 14:24:57 +02003168 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003169 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003170
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003171 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003172 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003173
Johan Hedberga664b5b2011-02-19 12:06:02 -03003174 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003175
3176 return err;
3177}
Johan Hedberga5c29682011-02-19 12:05:57 -03003178
Johan Hedberg744cf192011-11-08 20:40:14 +02003179int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180 u8 link_type, u8 addr_type, __le32 value,
3181 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003182{
3183 struct mgmt_ev_user_confirm_request ev;
3184
Johan Hedberg744cf192011-11-08 20:40:14 +02003185 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003186
Johan Hedberg272d90d2012-02-09 15:26:12 +02003187 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003188 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003189 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003190 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003191
Johan Hedberg744cf192011-11-08 20:40:14 +02003192 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003193 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003194}
3195
Johan Hedberg272d90d2012-02-09 15:26:12 +02003196int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003197 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003198{
3199 struct mgmt_ev_user_passkey_request ev;
3200
3201 BT_DBG("%s", hdev->name);
3202
Johan Hedberg272d90d2012-02-09 15:26:12 +02003203 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003204 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003205
3206 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003207 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003208}
3209
Brian Gix0df4c182011-11-16 13:53:13 -08003210static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003211 u8 link_type, u8 addr_type, u8 status,
3212 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003213{
3214 struct pending_cmd *cmd;
3215 struct mgmt_rp_user_confirm_reply rp;
3216 int err;
3217
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003218 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003219 if (!cmd)
3220 return -ENOENT;
3221
Johan Hedberg272d90d2012-02-09 15:26:12 +02003222 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003223 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003224 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003225 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003226
Johan Hedberga664b5b2011-02-19 12:06:02 -03003227 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003228
3229 return err;
3230}
3231
Johan Hedberg744cf192011-11-08 20:40:14 +02003232int mgmt_user_confirm_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 F. Padovan04124682012-03-08 01:25:00 -03003236 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003237}
3238
Johan Hedberg272d90d2012-02-09 15:26:12 +02003239int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003240 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003241{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003242 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003243 status,
3244 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003245}
Johan Hedberg2a611692011-02-19 12:06:00 -03003246
Brian Gix604086b2011-11-23 08:28:33 -08003247int mgmt_user_passkey_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 F. Padovan04124682012-03-08 01:25:00 -03003251 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003252}
3253
Johan Hedberg272d90d2012-02-09 15:26:12 +02003254int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003255 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003256{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003257 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003258 status,
3259 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003260}
3261
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003262int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003263 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003264{
3265 struct mgmt_ev_auth_failed ev;
3266
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003267 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003268 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003269 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003270
Johan Hedberg744cf192011-11-08 20:40:14 +02003271 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003272}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003273
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003274int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3275{
3276 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003277 bool changed = false;
3278 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003279
3280 if (status) {
3281 u8 mgmt_err = mgmt_status(status);
3282 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003283 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003284 return 0;
3285 }
3286
Johan Hedberg47990ea2012-02-22 11:58:37 +02003287 if (test_bit(HCI_AUTH, &hdev->flags)) {
3288 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3289 changed = true;
3290 } else {
3291 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3292 changed = true;
3293 }
3294
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003295 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003296 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003297
Johan Hedberg47990ea2012-02-22 11:58:37 +02003298 if (changed)
3299 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003300
3301 if (match.sk)
3302 sock_put(match.sk);
3303
3304 return err;
3305}
3306
Johan Hedbergcacaf522012-02-21 00:52:42 +02003307static int clear_eir(struct hci_dev *hdev)
3308{
3309 struct hci_cp_write_eir cp;
3310
3311 if (!(hdev->features[6] & LMP_EXT_INQ))
3312 return 0;
3313
Johan Hedbergc80da272012-02-22 15:38:48 +02003314 memset(hdev->eir, 0, sizeof(hdev->eir));
3315
Johan Hedbergcacaf522012-02-21 00:52:42 +02003316 memset(&cp, 0, sizeof(cp));
3317
3318 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3319}
3320
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003321int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003322{
3323 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003324 bool changed = false;
3325 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003326
3327 if (status) {
3328 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003329
3330 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003331 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003332 err = new_settings(hdev, NULL);
3333
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003334 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3335 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003336
3337 return err;
3338 }
3339
3340 if (enable) {
3341 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3342 changed = true;
3343 } else {
3344 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3345 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003346 }
3347
3348 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3349
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003350 if (changed)
3351 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003352
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003353 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003354 sock_put(match.sk);
3355
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003356 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3357 update_eir(hdev);
3358 else
3359 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003360
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003361 return err;
3362}
3363
Johan Hedberg90e70452012-02-23 23:09:40 +02003364static void class_rsp(struct pending_cmd *cmd, void *data)
3365{
3366 struct cmd_lookup *match = data;
3367
3368 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003369 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003370
3371 list_del(&cmd->list);
3372
3373 if (match->sk == NULL) {
3374 match->sk = cmd->sk;
3375 sock_hold(match->sk);
3376 }
3377
3378 mgmt_pending_free(cmd);
3379}
3380
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003381int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003382 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003383{
Johan Hedberg90e70452012-02-23 23:09:40 +02003384 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3385 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003386
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003387 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3388
Johan Hedberg90e70452012-02-23 23:09:40 +02003389 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3390 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3391 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3392
3393 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003394 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3395 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003396
3397 if (match.sk)
3398 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003399
3400 return err;
3401}
3402
Johan Hedberg744cf192011-11-08 20:40:14 +02003403int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003404{
3405 struct pending_cmd *cmd;
3406 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003407 bool changed = false;
3408 int err = 0;
3409
3410 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3411 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3412 changed = true;
3413 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003414
3415 memset(&ev, 0, sizeof(ev));
3416 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003417 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003418
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003419 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003420 if (!cmd)
3421 goto send_event;
3422
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003423 /* Always assume that either the short or the complete name has
3424 * changed if there was a pending mgmt command */
3425 changed = true;
3426
Johan Hedbergb312b1612011-03-16 14:29:37 +02003427 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003428 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003429 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003430 goto failed;
3431 }
3432
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003433 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003434 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003435 if (err < 0)
3436 goto failed;
3437
3438send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003439 if (changed)
3440 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003441 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003442
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003443 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003444
3445failed:
3446 if (cmd)
3447 mgmt_pending_remove(cmd);
3448 return err;
3449}
Szymon Jancc35938b2011-03-22 13:12:21 +01003450
Johan Hedberg744cf192011-11-08 20:40:14 +02003451int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003452 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003453{
3454 struct pending_cmd *cmd;
3455 int err;
3456
Johan Hedberg744cf192011-11-08 20:40:14 +02003457 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003458
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003459 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003460 if (!cmd)
3461 return -ENOENT;
3462
3463 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003464 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3465 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003466 } else {
3467 struct mgmt_rp_read_local_oob_data rp;
3468
3469 memcpy(rp.hash, hash, sizeof(rp.hash));
3470 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3471
Johan Hedberg744cf192011-11-08 20:40:14 +02003472 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003473 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3474 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003475 }
3476
3477 mgmt_pending_remove(cmd);
3478
3479 return err;
3480}
Johan Hedberge17acd42011-03-30 23:57:16 +03003481
Johan Hedberg06199cf2012-02-22 16:37:11 +02003482int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3483{
3484 struct cmd_lookup match = { NULL, hdev };
3485 bool changed = false;
3486 int err = 0;
3487
3488 if (status) {
3489 u8 mgmt_err = mgmt_status(status);
3490
3491 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003492 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003493 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003494
Szymon Jancd97dcb62012-03-16 16:02:56 +01003495 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3496 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003497
3498 return err;
3499 }
3500
3501 if (enable) {
3502 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3503 changed = true;
3504 } else {
3505 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3506 changed = true;
3507 }
3508
3509 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3510
3511 if (changed)
3512 err = new_settings(hdev, match.sk);
3513
3514 if (match.sk)
3515 sock_put(match.sk);
3516
3517 return err;
3518}
3519
Johan Hedberg48264f02011-11-09 13:58:58 +02003520int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003521 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3522 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003523{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003524 char buf[512];
3525 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003526 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003527
Johan Hedberg1dc06092012-01-15 21:01:23 +02003528 /* Leave 5 bytes for a potential CoD field */
3529 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003530 return -EINVAL;
3531
Johan Hedberg1dc06092012-01-15 21:01:23 +02003532 memset(buf, 0, sizeof(buf));
3533
Johan Hedberge319d2e2012-01-15 19:51:59 +02003534 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003535 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003536 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003537 if (cfm_name)
Andrei Emeltchenko33cef262012-06-18 13:03:46 +03003538 ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003539 if (!ssp)
Andrei Emeltchenko33cef262012-06-18 13:03:46 +03003540 ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003541
Johan Hedberg1dc06092012-01-15 21:01:23 +02003542 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003543 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003544
Johan Hedberg1dc06092012-01-15 21:01:23 +02003545 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3546 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003547 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003548
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003549 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003550 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003551
Johan Hedberge319d2e2012-01-15 19:51:59 +02003552 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003553}
Johan Hedberga88a9652011-03-30 13:18:12 +03003554
Johan Hedbergb644ba32012-01-17 21:48:47 +02003555int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003556 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003557{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003558 struct mgmt_ev_device_found *ev;
3559 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3560 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003561
Johan Hedbergb644ba32012-01-17 21:48:47 +02003562 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003563
Johan Hedbergb644ba32012-01-17 21:48:47 +02003564 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003565
Johan Hedbergb644ba32012-01-17 21:48:47 +02003566 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003567 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003568 ev->rssi = rssi;
3569
3570 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003571 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003572
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003573 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003574
Johan Hedberg053c7e02012-02-04 00:06:00 +02003575 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003576 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003577}
Johan Hedberg314b2382011-04-27 10:29:57 -04003578
Andre Guedes7a135102011-11-09 17:14:25 -03003579int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003580{
3581 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003582 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003583 int err;
3584
Andre Guedes203159d2012-02-13 15:41:01 -03003585 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3586
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003587 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003588 if (!cmd)
3589 return -ENOENT;
3590
Johan Hedbergf808e162012-02-19 12:52:07 +02003591 type = hdev->discovery.type;
3592
3593 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003594 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003595 mgmt_pending_remove(cmd);
3596
3597 return err;
3598}
3599
Andre Guedese6d465c2011-11-09 17:14:26 -03003600int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3601{
3602 struct pending_cmd *cmd;
3603 int err;
3604
3605 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3606 if (!cmd)
3607 return -ENOENT;
3608
Johan Hedbergd9306502012-02-20 23:25:18 +02003609 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003610 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003611 mgmt_pending_remove(cmd);
3612
3613 return err;
3614}
Johan Hedberg314b2382011-04-27 10:29:57 -04003615
Johan Hedberg744cf192011-11-08 20:40:14 +02003616int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003617{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003618 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003619 struct pending_cmd *cmd;
3620
Andre Guedes343fb142011-11-22 17:14:19 -03003621 BT_DBG("%s discovering %u", hdev->name, discovering);
3622
Johan Hedberg164a6e72011-11-01 17:06:44 +02003623 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003624 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003625 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003626 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003627
3628 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003629 u8 type = hdev->discovery.type;
3630
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003631 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3632 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003633 mgmt_pending_remove(cmd);
3634 }
3635
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003636 memset(&ev, 0, sizeof(ev));
3637 ev.type = hdev->discovery.type;
3638 ev.discovering = discovering;
3639
3640 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003641}
Antti Julku5e762442011-08-25 16:48:02 +03003642
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003643int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003644{
3645 struct pending_cmd *cmd;
3646 struct mgmt_ev_device_blocked ev;
3647
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003648 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003649
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003650 bacpy(&ev.addr.bdaddr, bdaddr);
3651 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003652
Johan Hedberg744cf192011-11-08 20:40:14 +02003653 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003654 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003655}
3656
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003657int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003658{
3659 struct pending_cmd *cmd;
3660 struct mgmt_ev_device_unblocked ev;
3661
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003662 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003663
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003664 bacpy(&ev.addr.bdaddr, bdaddr);
3665 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003666
Johan Hedberg744cf192011-11-08 20:40:14 +02003667 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003668 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003669}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003670
3671module_param(enable_hs, bool, 0644);
3672MODULE_PARM_DESC(enable_hs, "Enable High Speed support");