blob: 087cf00a443d983de61d76c2c4187e79ed53c966 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020027#include <asm/unaligned.h>
28
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/mgmt.h>
32
Johan Hedberg02d98122010-12-13 21:07:04 +020033#define MGMT_VERSION 0
34#define MGMT_REVISION 1
35
Andre Guedes2519a1f2011-11-07 11:45:24 -030036#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
37
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020038struct pending_cmd {
39 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020040 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020041 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010042 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020043 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030044 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045};
46
Johan Hedbergca69b792011-11-11 18:10:00 +020047/* HCI to MGMT error code conversion table */
48static u8 mgmt_status_table[] = {
49 MGMT_STATUS_SUCCESS,
50 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
51 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
52 MGMT_STATUS_FAILED, /* Hardware Failure */
53 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
54 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
55 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
56 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
57 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
58 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
59 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
60 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
61 MGMT_STATUS_BUSY, /* Command Disallowed */
62 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
63 MGMT_STATUS_REJECTED, /* Rejected Security */
64 MGMT_STATUS_REJECTED, /* Rejected Personal */
65 MGMT_STATUS_TIMEOUT, /* Host Timeout */
66 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
67 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
68 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
69 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
70 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
71 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
72 MGMT_STATUS_BUSY, /* Repeated Attempts */
73 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
74 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
75 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
76 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
77 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
78 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
79 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
80 MGMT_STATUS_FAILED, /* Unspecified Error */
81 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
82 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
83 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
84 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
85 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
86 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
87 MGMT_STATUS_FAILED, /* Unit Link Key Used */
88 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
89 MGMT_STATUS_TIMEOUT, /* Instant Passed */
90 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
91 MGMT_STATUS_FAILED, /* Transaction Collision */
92 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
93 MGMT_STATUS_REJECTED, /* QoS Rejected */
94 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
95 MGMT_STATUS_REJECTED, /* Insufficient Security */
96 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
97 MGMT_STATUS_BUSY, /* Role Switch Pending */
98 MGMT_STATUS_FAILED, /* Slot Violation */
99 MGMT_STATUS_FAILED, /* Role Switch Failed */
100 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
101 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
102 MGMT_STATUS_BUSY, /* Host Busy Pairing */
103 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
104 MGMT_STATUS_BUSY, /* Controller Busy */
105 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
106 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
107 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
108 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
109 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
110};
111
112static u8 mgmt_status(u8 hci_status)
113{
114 if (hci_status < ARRAY_SIZE(mgmt_status_table))
115 return mgmt_status_table[hci_status];
116
117 return MGMT_STATUS_FAILED;
118}
119
Szymon Janc4e51eae2011-02-25 19:05:48 +0100120static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200121{
122 struct sk_buff *skb;
123 struct mgmt_hdr *hdr;
124 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300125 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200126
Szymon Janc34eb5252011-02-28 14:10:08 +0100127 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200128
129 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
130 if (!skb)
131 return -ENOMEM;
132
133 hdr = (void *) skb_put(skb, sizeof(*hdr));
134
135 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100136 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200137 hdr->len = cpu_to_le16(sizeof(*ev));
138
139 ev = (void *) skb_put(skb, sizeof(*ev));
140 ev->status = status;
141 put_unaligned_le16(cmd, &ev->opcode);
142
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300143 err = sock_queue_rcv_skb(sk, skb);
144 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200145 kfree_skb(skb);
146
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300147 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200148}
149
Szymon Janc4e51eae2011-02-25 19:05:48 +0100150static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
151 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200152{
153 struct sk_buff *skb;
154 struct mgmt_hdr *hdr;
155 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300156 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200157
158 BT_DBG("sock %p", sk);
159
Johan Hedberga38528f2011-01-22 06:46:43 +0200160 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200161 if (!skb)
162 return -ENOMEM;
163
164 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200165
Johan Hedberg02d98122010-12-13 21:07:04 +0200166 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100167 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200168 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200169
Johan Hedberga38528f2011-01-22 06:46:43 +0200170 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
171 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100172
173 if (rp)
174 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200175
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300176 err = sock_queue_rcv_skb(sk, skb);
177 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200178 kfree_skb(skb);
179
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300180 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200181}
182
Johan Hedberga38528f2011-01-22 06:46:43 +0200183static int read_version(struct sock *sk)
184{
185 struct mgmt_rp_read_version rp;
186
187 BT_DBG("sock %p", sk);
188
189 rp.version = MGMT_VERSION;
190 put_unaligned_le16(MGMT_REVISION, &rp.revision);
191
Szymon Janc4e51eae2011-02-25 19:05:48 +0100192 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
193 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200194}
195
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200196static int read_index_list(struct sock *sk)
197{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200198 struct mgmt_rp_read_index_list *rp;
199 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200200 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200202 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200204
205 BT_DBG("sock %p", sk);
206
207 read_lock(&hci_dev_list_lock);
208
209 count = 0;
210 list_for_each(p, &hci_dev_list) {
211 count++;
212 }
213
Johan Hedberga38528f2011-01-22 06:46:43 +0200214 rp_len = sizeof(*rp) + (2 * count);
215 rp = kmalloc(rp_len, GFP_ATOMIC);
216 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100217 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200218 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100219 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200220
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200221 put_unaligned_le16(count, &rp->num_controllers);
222
223 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200224 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200225 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200226 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200227
228 if (test_bit(HCI_SETUP, &d->flags))
229 continue;
230
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200231 put_unaligned_le16(d->id, &rp->index[i++]);
232 BT_DBG("Added hci%u", d->id);
233 }
234
235 read_unlock(&hci_dev_list_lock);
236
Szymon Janc4e51eae2011-02-25 19:05:48 +0100237 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
238 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200239
Johan Hedberga38528f2011-01-22 06:46:43 +0200240 kfree(rp);
241
242 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200243}
244
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200245static u32 get_supported_settings(struct hci_dev *hdev)
246{
247 u32 settings = 0;
248
249 settings |= MGMT_SETTING_POWERED;
250 settings |= MGMT_SETTING_CONNECTABLE;
251 settings |= MGMT_SETTING_FAST_CONNECTABLE;
252 settings |= MGMT_SETTING_DISCOVERABLE;
253 settings |= MGMT_SETTING_PAIRABLE;
254
255 if (hdev->features[6] & LMP_SIMPLE_PAIR)
256 settings |= MGMT_SETTING_SSP;
257
258 if (!(hdev->features[4] & LMP_NO_BREDR)) {
259 settings |= MGMT_SETTING_BREDR;
260 settings |= MGMT_SETTING_LINK_SECURITY;
261 }
262
263 if (hdev->features[4] & LMP_LE)
264 settings |= MGMT_SETTING_LE;
265
266 return settings;
267}
268
269static u32 get_current_settings(struct hci_dev *hdev)
270{
271 u32 settings = 0;
272
273 if (test_bit(HCI_UP, &hdev->flags))
274 settings |= MGMT_SETTING_POWERED;
275 else
276 return settings;
277
278 if (test_bit(HCI_PSCAN, &hdev->flags))
279 settings |= MGMT_SETTING_CONNECTABLE;
280
281 if (test_bit(HCI_ISCAN, &hdev->flags))
282 settings |= MGMT_SETTING_DISCOVERABLE;
283
284 if (test_bit(HCI_PAIRABLE, &hdev->flags))
285 settings |= MGMT_SETTING_PAIRABLE;
286
287 if (!(hdev->features[4] & LMP_NO_BREDR))
288 settings |= MGMT_SETTING_BREDR;
289
290 if (hdev->extfeatures[0] & LMP_HOST_LE)
291 settings |= MGMT_SETTING_LE;
292
293 if (test_bit(HCI_AUTH, &hdev->flags))
294 settings |= MGMT_SETTING_LINK_SECURITY;
295
296 if (hdev->ssp_mode > 0)
297 settings |= MGMT_SETTING_SSP;
298
299 return settings;
300}
301
Szymon Janc4e51eae2011-02-25 19:05:48 +0100302static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200303{
Johan Hedberga38528f2011-01-22 06:46:43 +0200304 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200305 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200306
Szymon Janc4e51eae2011-02-25 19:05:48 +0100307 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200308
Szymon Janc4e51eae2011-02-25 19:05:48 +0100309 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200310 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200311 return cmd_status(sk, index, MGMT_OP_READ_INFO,
312 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200313
Johan Hedberg32435532011-11-07 22:16:04 +0200314 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
315 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200316
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300317 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200318
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200319 set_bit(HCI_MGMT, &hdev->flags);
320
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200321 memset(&rp, 0, sizeof(rp));
322
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200324
325 rp.version = hdev->hci_ver;
326
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200328
329 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
330 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
331
332 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200333
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200334 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
335
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300336 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200337 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200338
Szymon Janc4e51eae2011-02-25 19:05:48 +0100339 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200340}
341
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200342static void mgmt_pending_free(struct pending_cmd *cmd)
343{
344 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100345 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346 kfree(cmd);
347}
348
Johan Hedberg366a0332011-02-19 12:05:55 -0300349static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200350 struct hci_dev *hdev,
351 void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200352{
353 struct pending_cmd *cmd;
354
355 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
356 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300357 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200358
359 cmd->opcode = opcode;
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200360 cmd->index = hdev->id;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200361
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100362 cmd->param = kmalloc(len, GFP_ATOMIC);
363 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200364 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300365 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200366 }
367
Szymon Janc8fce6352011-03-22 13:12:20 +0100368 if (data)
369 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200370
371 cmd->sk = sk;
372 sock_hold(sk);
373
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200374 list_add(&cmd->list, &hdev->mgmt_pending);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200375
Johan Hedberg366a0332011-02-19 12:05:55 -0300376 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200377}
378
Johan Hedberg744cf192011-11-08 20:40:14 +0200379static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200380 void (*cb)(struct pending_cmd *cmd, void *data),
381 void *data)
382{
383 struct list_head *p, *n;
384
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200385 list_for_each_safe(p, n, &hdev->mgmt_pending) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200386 struct pending_cmd *cmd;
387
388 cmd = list_entry(p, struct pending_cmd, list);
389
Johan Hedbergb24752f2011-11-03 14:40:33 +0200390 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200391 continue;
392
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200393 cb(cmd, data);
394 }
395}
396
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200397static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200398{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200399 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200400
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200401 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg2aeabcb2011-11-09 13:58:57 +0200402 if (cmd->opcode == opcode)
403 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200404 }
405
406 return NULL;
407}
408
Johan Hedberga664b5b2011-02-19 12:06:02 -0300409static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200410{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200411 list_del(&cmd->list);
412 mgmt_pending_free(cmd);
413}
414
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200416{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200418
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200420}
421
Szymon Janc4e51eae2011-02-25 19:05:48 +0100422static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200423{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200424 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200425 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300426 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300427 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200428
429 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200430
Szymon Janc4e51eae2011-02-25 19:05:48 +0100431 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200432
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100433 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200434 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
435 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100436
Szymon Janc4e51eae2011-02-25 19:05:48 +0100437 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200438 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200439 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
440 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200441
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300442 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200443
444 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200445 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200446 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200447 goto failed;
448 }
449
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200450 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200451 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
452 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200453 goto failed;
454 }
455
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200456 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300457 if (!cmd) {
458 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200459 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300460 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200461
Johan Hedberg72a734e2010-12-30 00:38:22 +0200462 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200463 schedule_work(&hdev->power_on);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200464 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200465 schedule_work(&hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200466
Johan Hedberg366a0332011-02-19 12:05:55 -0300467 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200468
469failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300470 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200471 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300472 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200473}
474
Szymon Janc4e51eae2011-02-25 19:05:48 +0100475static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
476 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200477{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200478 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200479 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300480 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200481 u8 scan;
482 int err;
483
484 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200485
Szymon Janc4e51eae2011-02-25 19:05:48 +0100486 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200487
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100488 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200489 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
490 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100491
Szymon Janc4e51eae2011-02-25 19:05:48 +0100492 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200493 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200494 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
495 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200496
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300497 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200498
499 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200500 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
501 MGMT_STATUS_NOT_POWERED);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200502 goto failed;
503 }
504
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200505 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
506 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200507 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
508 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200509 goto failed;
510 }
511
Johan Hedberg72a734e2010-12-30 00:38:22 +0200512 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200513 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200514 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200515 goto failed;
516 }
517
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200518 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300519 if (!cmd) {
520 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200521 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300522 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200523
524 scan = SCAN_PAGE;
525
Johan Hedberg72a734e2010-12-30 00:38:22 +0200526 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200527 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200528 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200529 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200530
531 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
532 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300533 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200534
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200535 if (cp->val)
536 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
537
Johan Hedberg73f22f62010-12-29 16:00:25 +0200538failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300539 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200540 hci_dev_put(hdev);
541
542 return err;
543}
544
Szymon Janc4e51eae2011-02-25 19:05:48 +0100545static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
546 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200547{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200548 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200549 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300550 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200551 u8 scan;
552 int err;
553
554 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200555
Szymon Janc4e51eae2011-02-25 19:05:48 +0100556 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200557
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100558 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200559 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
560 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100561
Szymon Janc4e51eae2011-02-25 19:05:48 +0100562 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200563 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200564 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
565 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200566
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300567 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200568
569 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200570 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
571 MGMT_STATUS_NOT_POWERED);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200572 goto failed;
573 }
574
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200575 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
576 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200577 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
578 MGMT_STATUS_BUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200579 goto failed;
580 }
581
Johan Hedberg72a734e2010-12-30 00:38:22 +0200582 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200583 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200584 goto failed;
585 }
586
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200587 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300588 if (!cmd) {
589 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200590 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300591 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200592
Johan Hedberg72a734e2010-12-30 00:38:22 +0200593 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200594 scan = SCAN_PAGE;
595 else
596 scan = 0;
597
598 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
599 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300600 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200601
602failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300603 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200604 hci_dev_put(hdev);
605
606 return err;
607}
608
Johan Hedberg744cf192011-11-08 20:40:14 +0200609static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
610 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200611{
612 struct sk_buff *skb;
613 struct mgmt_hdr *hdr;
614
615 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
616 if (!skb)
617 return -ENOMEM;
618
619 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
620
621 hdr = (void *) skb_put(skb, sizeof(*hdr));
622 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200623 if (hdev)
624 hdr->index = cpu_to_le16(hdev->id);
625 else
626 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200627 hdr->len = cpu_to_le16(data_len);
628
Szymon Janc4e51eae2011-02-25 19:05:48 +0100629 if (data)
630 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200631
632 hci_send_to_sock(NULL, skb, skip_sk);
633 kfree_skb(skb);
634
635 return 0;
636}
637
Szymon Janc4e51eae2011-02-25 19:05:48 +0100638static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
639 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200640{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200641 struct mgmt_mode *cp;
Johan Hedbergc542a062011-01-26 13:11:03 +0200642 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200643 __le32 ev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200644 int err;
645
646 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200647
Szymon Janc4e51eae2011-02-25 19:05:48 +0100648 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200649
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100650 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200651 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
652 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100653
Szymon Janc4e51eae2011-02-25 19:05:48 +0100654 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200655 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200656 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
657 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergc542a062011-01-26 13:11:03 +0200658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300659 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200660
661 if (cp->val)
662 set_bit(HCI_PAIRABLE, &hdev->flags);
663 else
664 clear_bit(HCI_PAIRABLE, &hdev->flags);
665
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200666 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200667 if (err < 0)
668 goto failed;
669
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200670 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergc542a062011-01-26 13:11:03 +0200671
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200673
674failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300675 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200676 hci_dev_put(hdev);
677
678 return err;
679}
680
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300681#define EIR_FLAGS 0x01 /* flags */
682#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
683#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
684#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
685#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
686#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
687#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
688#define EIR_NAME_SHORT 0x08 /* shortened local name */
689#define EIR_NAME_COMPLETE 0x09 /* complete local name */
690#define EIR_TX_POWER 0x0A /* transmit power level */
691#define EIR_DEVICE_ID 0x10 /* device ID */
692
693#define PNP_INFO_SVCLASS_ID 0x1200
694
695static u8 bluetooth_base_uuid[] = {
696 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
697 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
698};
699
700static u16 get_uuid16(u8 *uuid128)
701{
702 u32 val;
703 int i;
704
705 for (i = 0; i < 12; i++) {
706 if (bluetooth_base_uuid[i] != uuid128[i])
707 return 0;
708 }
709
710 memcpy(&val, &uuid128[12], 4);
711
712 val = le32_to_cpu(val);
713 if (val > 0xffff)
714 return 0;
715
716 return (u16) val;
717}
718
719static void create_eir(struct hci_dev *hdev, u8 *data)
720{
721 u8 *ptr = data;
722 u16 eir_len = 0;
723 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
724 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200725 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300726 size_t name_len;
727
728 name_len = strlen(hdev->dev_name);
729
730 if (name_len > 0) {
731 /* EIR Data type */
732 if (name_len > 48) {
733 name_len = 48;
734 ptr[1] = EIR_NAME_SHORT;
735 } else
736 ptr[1] = EIR_NAME_COMPLETE;
737
738 /* EIR Data length */
739 ptr[0] = name_len + 1;
740
741 memcpy(ptr + 2, hdev->dev_name, name_len);
742
743 eir_len += (name_len + 2);
744 ptr += (name_len + 2);
745 }
746
747 memset(uuid16_list, 0, sizeof(uuid16_list));
748
749 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200750 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300751 u16 uuid16;
752
753 uuid16 = get_uuid16(uuid->uuid);
754 if (uuid16 == 0)
755 return;
756
757 if (uuid16 < 0x1100)
758 continue;
759
760 if (uuid16 == PNP_INFO_SVCLASS_ID)
761 continue;
762
763 /* Stop if not enough space to put next UUID */
764 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
765 truncated = 1;
766 break;
767 }
768
769 /* Check for duplicates */
770 for (i = 0; uuid16_list[i] != 0; i++)
771 if (uuid16_list[i] == uuid16)
772 break;
773
774 if (uuid16_list[i] == 0) {
775 uuid16_list[i] = uuid16;
776 eir_len += sizeof(u16);
777 }
778 }
779
780 if (uuid16_list[0] != 0) {
781 u8 *length = ptr;
782
783 /* EIR Data type */
784 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
785
786 ptr += 2;
787 eir_len += 2;
788
789 for (i = 0; uuid16_list[i] != 0; i++) {
790 *ptr++ = (uuid16_list[i] & 0x00ff);
791 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
792 }
793
794 /* EIR Data length */
795 *length = (i * sizeof(u16)) + 1;
796 }
797}
798
799static int update_eir(struct hci_dev *hdev)
800{
801 struct hci_cp_write_eir cp;
802
803 if (!(hdev->features[6] & LMP_EXT_INQ))
804 return 0;
805
806 if (hdev->ssp_mode == 0)
807 return 0;
808
809 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
810 return 0;
811
812 memset(&cp, 0, sizeof(cp));
813
814 create_eir(hdev, cp.data);
815
816 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
817 return 0;
818
819 memcpy(hdev->eir, cp.data, sizeof(cp.data));
820
821 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
822}
823
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200824static u8 get_service_classes(struct hci_dev *hdev)
825{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300826 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200827 u8 val = 0;
828
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300829 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200830 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200831
832 return val;
833}
834
835static int update_class(struct hci_dev *hdev)
836{
837 u8 cod[3];
838
839 BT_DBG("%s", hdev->name);
840
841 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
842 return 0;
843
844 cod[0] = hdev->minor_class;
845 cod[1] = hdev->major_class;
846 cod[2] = get_service_classes(hdev);
847
848 if (memcmp(cod, hdev->dev_class, 3) == 0)
849 return 0;
850
851 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
852}
853
Szymon Janc4e51eae2011-02-25 19:05:48 +0100854static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200855{
856 struct mgmt_cp_add_uuid *cp;
857 struct hci_dev *hdev;
858 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200859 int err;
860
861 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200862
Szymon Janc4e51eae2011-02-25 19:05:48 +0100863 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200864
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100865 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200866 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
867 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100868
Szymon Janc4e51eae2011-02-25 19:05:48 +0100869 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200870 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200871 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
872 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200873
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300874 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200875
876 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
877 if (!uuid) {
878 err = -ENOMEM;
879 goto failed;
880 }
881
882 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200883 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200884
885 list_add(&uuid->list, &hdev->uuids);
886
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200887 err = update_class(hdev);
888 if (err < 0)
889 goto failed;
890
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300891 err = update_eir(hdev);
892 if (err < 0)
893 goto failed;
894
Szymon Janc4e51eae2011-02-25 19:05:48 +0100895 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200896
897failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300898 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200899 hci_dev_put(hdev);
900
901 return err;
902}
903
Szymon Janc4e51eae2011-02-25 19:05:48 +0100904static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200905{
906 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100907 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200908 struct hci_dev *hdev;
909 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 +0200910 int err, found;
911
912 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200915
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100916 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200917 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
918 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100919
Szymon Janc4e51eae2011-02-25 19:05:48 +0100920 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200921 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200922 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
923 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200924
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300925 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200926
927 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
928 err = hci_uuids_clear(hdev);
929 goto unlock;
930 }
931
932 found = 0;
933
934 list_for_each_safe(p, n, &hdev->uuids) {
935 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
936
937 if (memcmp(match->uuid, cp->uuid, 16) != 0)
938 continue;
939
940 list_del(&match->list);
941 found++;
942 }
943
944 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200945 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
946 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200947 goto unlock;
948 }
949
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200950 err = update_class(hdev);
951 if (err < 0)
952 goto unlock;
953
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300954 err = update_eir(hdev);
955 if (err < 0)
956 goto unlock;
957
Szymon Janc4e51eae2011-02-25 19:05:48 +0100958 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200959
960unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300961 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200962 hci_dev_put(hdev);
963
964 return err;
965}
966
Szymon Janc4e51eae2011-02-25 19:05:48 +0100967static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
968 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200969{
970 struct hci_dev *hdev;
971 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200972 int err;
973
974 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200975
Szymon Janc4e51eae2011-02-25 19:05:48 +0100976 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200977
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100978 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200979 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
980 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100981
Szymon Janc4e51eae2011-02-25 19:05:48 +0100982 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200983 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200984 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
985 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200986
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300987 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200988
989 hdev->major_class = cp->major;
990 hdev->minor_class = cp->minor;
991
992 err = update_class(hdev);
993
994 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100995 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200996
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300997 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998 hci_dev_put(hdev);
999
1000 return err;
1001}
1002
Szymon Janc4e51eae2011-02-25 19:05:48 +01001003static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
1004 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001005{
1006 struct hci_dev *hdev;
1007 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001008 int err;
1009
1010 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001011
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001012 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001013 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
1014 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001015
Szymon Janc4e51eae2011-02-25 19:05:48 +01001016 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001017 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001018 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
1019 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001020
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001021 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001022
Szymon Janc4e51eae2011-02-25 19:05:48 +01001023 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001024
1025 if (cp->enable) {
1026 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
1027 err = 0;
1028 } else {
1029 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
1030 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001031 if (err == 0)
1032 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001033 }
1034
1035 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001036 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
1037 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -03001038 else
1039 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
1040
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001041
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001042 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001043 hci_dev_put(hdev);
1044
1045 return err;
1046}
1047
Johan Hedberg86742e12011-11-07 23:13:38 +02001048static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1049 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001050{
1051 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001052 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001053 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001054 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001055
1056 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001057
1058 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001059 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1060 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001061
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001062 key_count = get_unaligned_le16(&cp->key_count);
1063
Johan Hedberg86742e12011-11-07 23:13:38 +02001064 expected_len = sizeof(*cp) + key_count *
1065 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001066 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001067 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001068 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001069 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1070 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001071 }
1072
Szymon Janc4e51eae2011-02-25 19:05:48 +01001073 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001074 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001075 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1076 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001077
Szymon Janc4e51eae2011-02-25 19:05:48 +01001078 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001079 key_count);
1080
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001081 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001082
1083 hci_link_keys_clear(hdev);
1084
1085 set_bit(HCI_LINK_KEYS, &hdev->flags);
1086
1087 if (cp->debug_keys)
1088 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1089 else
1090 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1091
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001092 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001093 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001094
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001095 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001096 key->pin_len);
1097 }
1098
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001099 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1100
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001101 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001102 hci_dev_put(hdev);
1103
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001104 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001105}
1106
Johan Hedberg86742e12011-11-07 23:13:38 +02001107static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1108 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001109{
1110 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001111 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001112 struct mgmt_rp_remove_keys rp;
1113 struct hci_cp_disconnect dc;
1114 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001115 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001116 int err;
1117
1118 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001119
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001120 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001121 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1122 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001123
Szymon Janc4e51eae2011-02-25 19:05:48 +01001124 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001125 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001126 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1127 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001128
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001129 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001130
Johan Hedberga8a1d192011-11-10 15:54:38 +02001131 memset(&rp, 0, sizeof(rp));
1132 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001133 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001134
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001135 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001136 if (err < 0) {
1137 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001138 goto unlock;
Johan Hedbergca69b792011-11-11 18:10:00 +02001139 }
Johan Hedberga8a1d192011-11-10 15:54:38 +02001140
1141 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1142 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1143 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001144 goto unlock;
1145 }
1146
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001147 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001148 if (!conn) {
1149 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1150 sizeof(rp));
1151 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001152 }
1153
Johan Hedberga8a1d192011-11-10 15:54:38 +02001154 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1155 if (!cmd) {
1156 err = -ENOMEM;
1157 goto unlock;
1158 }
1159
1160 put_unaligned_le16(conn->handle, &dc.handle);
1161 dc.reason = 0x13; /* Remote User Terminated Connection */
1162 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1163 if (err < 0)
1164 mgmt_pending_remove(cmd);
1165
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001166unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001167 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001168 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1169 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001170 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001171 hci_dev_put(hdev);
1172
1173 return err;
1174}
1175
Szymon Janc4e51eae2011-02-25 19:05:48 +01001176static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001177{
1178 struct hci_dev *hdev;
1179 struct mgmt_cp_disconnect *cp;
1180 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001181 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001182 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001183 int err;
1184
1185 BT_DBG("");
1186
1187 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001188
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001189 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001190 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1191 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001192
Szymon Janc4e51eae2011-02-25 19:05:48 +01001193 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001194 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001195 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1196 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001197
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001198 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001199
1200 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001201 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1202 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001203 goto failed;
1204 }
1205
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001206 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001207 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1208 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001209 goto failed;
1210 }
1211
1212 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001213 if (!conn)
1214 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1215
Johan Hedberg8962ee72011-01-20 12:40:27 +02001216 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001217 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1218 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001219 goto failed;
1220 }
1221
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001222 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001223 if (!cmd) {
1224 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001225 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001226 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001227
1228 put_unaligned_le16(conn->handle, &dc.handle);
1229 dc.reason = 0x13; /* Remote User Terminated Connection */
1230
1231 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1232 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001233 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001234
1235failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001236 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001237 hci_dev_put(hdev);
1238
1239 return err;
1240}
1241
Johan Hedberg48264f02011-11-09 13:58:58 +02001242static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001243{
1244 switch (link_type) {
1245 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001246 switch (addr_type) {
1247 case ADDR_LE_DEV_PUBLIC:
1248 return MGMT_ADDR_LE_PUBLIC;
1249 case ADDR_LE_DEV_RANDOM:
1250 return MGMT_ADDR_LE_RANDOM;
1251 default:
1252 return MGMT_ADDR_INVALID;
1253 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001254 case ACL_LINK:
1255 return MGMT_ADDR_BREDR;
1256 default:
1257 return MGMT_ADDR_INVALID;
1258 }
1259}
1260
Szymon Janc8ce62842011-03-01 16:55:32 +01001261static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001262{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001263 struct mgmt_rp_get_connections *rp;
1264 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001265 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001266 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001267 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001268 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001269 int i, err;
1270
1271 BT_DBG("");
1272
Szymon Janc4e51eae2011-02-25 19:05:48 +01001273 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001274 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001275 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1276 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001277
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001278 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001279
1280 count = 0;
1281 list_for_each(p, &hdev->conn_hash.list) {
1282 count++;
1283 }
1284
Johan Hedberg4c659c32011-11-07 23:13:39 +02001285 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001286 rp = kmalloc(rp_len, GFP_ATOMIC);
1287 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001288 err = -ENOMEM;
1289 goto unlock;
1290 }
1291
Johan Hedberg2784eb42011-01-21 13:56:35 +02001292 put_unaligned_le16(count, &rp->conn_count);
1293
Johan Hedberg2784eb42011-01-21 13:56:35 +02001294 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001295 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1296 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001297 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001298 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1299 continue;
1300 i++;
1301 }
1302
1303 /* Recalculate length in case of filtered SCO connections, etc */
1304 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001305
Szymon Janc4e51eae2011-02-25 19:05:48 +01001306 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001307
1308unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001309 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001310 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001311 hci_dev_put(hdev);
1312 return err;
1313}
1314
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001315static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1316 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1317{
1318 struct pending_cmd *cmd;
1319 int err;
1320
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001321 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001322 sizeof(*cp));
1323 if (!cmd)
1324 return -ENOMEM;
1325
1326 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1327 &cp->bdaddr);
1328 if (err < 0)
1329 mgmt_pending_remove(cmd);
1330
1331 return err;
1332}
1333
Szymon Janc4e51eae2011-02-25 19:05:48 +01001334static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1335 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001336{
1337 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001338 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001339 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001340 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001341 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001342 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001343 int err;
1344
1345 BT_DBG("");
1346
1347 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001348
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001349 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001350 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1351 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001352
Szymon Janc4e51eae2011-02-25 19:05:48 +01001353 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001354 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001355 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1356 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001357
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001358 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001359
1360 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001361 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1362 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001363 goto failed;
1364 }
1365
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001366 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1367 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001368 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1369 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001370 goto failed;
1371 }
1372
1373 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1374 bacpy(&ncp.bdaddr, &cp->bdaddr);
1375
1376 BT_ERR("PIN code is not 16 bytes long");
1377
1378 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1379 if (err >= 0)
1380 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001381 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001382
1383 goto failed;
1384 }
1385
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001386 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001387 if (!cmd) {
1388 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001389 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001390 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001391
1392 bacpy(&reply.bdaddr, &cp->bdaddr);
1393 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001394 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001395
1396 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1397 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001398 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001399
1400failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001401 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001402 hci_dev_put(hdev);
1403
1404 return err;
1405}
1406
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1408 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001409{
1410 struct hci_dev *hdev;
1411 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001412 int err;
1413
1414 BT_DBG("");
1415
1416 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001417
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001418 if (len != sizeof(*cp))
1419 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001420 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001421
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001423 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001424 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001425 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001426
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001427 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001428
1429 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001430 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001431 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001432 goto failed;
1433 }
1434
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001435 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001436
1437failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001438 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001439 hci_dev_put(hdev);
1440
1441 return err;
1442}
1443
Szymon Janc4e51eae2011-02-25 19:05:48 +01001444static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1445 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001446{
1447 struct hci_dev *hdev;
1448 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001449
1450 BT_DBG("");
1451
1452 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001453
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001454 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001455 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1456 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001457
Szymon Janc4e51eae2011-02-25 19:05:48 +01001458 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001459 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001460 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1461 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001463 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001464
1465 hdev->io_capability = cp->io_capability;
1466
1467 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001468 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001469
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001470 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001471 hci_dev_put(hdev);
1472
Szymon Janc4e51eae2011-02-25 19:05:48 +01001473 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001474}
1475
Johan Hedberge9a416b2011-02-19 12:05:56 -03001476static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1477{
1478 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001479 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001480
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001481 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001482 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1483 continue;
1484
Johan Hedberge9a416b2011-02-19 12:05:56 -03001485 if (cmd->user_data != conn)
1486 continue;
1487
1488 return cmd;
1489 }
1490
1491 return NULL;
1492}
1493
1494static void pairing_complete(struct pending_cmd *cmd, u8 status)
1495{
1496 struct mgmt_rp_pair_device rp;
1497 struct hci_conn *conn = cmd->user_data;
1498
Johan Hedbergba4e5642011-11-11 00:07:34 +02001499 bacpy(&rp.addr.bdaddr, &conn->dst);
1500 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001501 rp.status = status;
1502
Szymon Janc4e51eae2011-02-25 19:05:48 +01001503 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001504
1505 /* So we don't get further callbacks for this connection */
1506 conn->connect_cfm_cb = NULL;
1507 conn->security_cfm_cb = NULL;
1508 conn->disconn_cfm_cb = NULL;
1509
1510 hci_conn_put(conn);
1511
Johan Hedberga664b5b2011-02-19 12:06:02 -03001512 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001513}
1514
1515static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1516{
1517 struct pending_cmd *cmd;
1518
1519 BT_DBG("status %u", status);
1520
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001521 cmd = find_pairing(conn);
1522 if (!cmd)
1523 BT_DBG("Unable to find a pending command");
1524 else
1525 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001526}
1527
Szymon Janc4e51eae2011-02-25 19:05:48 +01001528static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001529{
1530 struct hci_dev *hdev;
1531 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001532 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001533 struct pending_cmd *cmd;
1534 u8 sec_level, auth_type;
1535 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001536 int err;
1537
1538 BT_DBG("");
1539
1540 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001541
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001542 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001543 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1544 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001545
Szymon Janc4e51eae2011-02-25 19:05:48 +01001546 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001547 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001548 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1549 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001550
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001551 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001552
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001553 sec_level = BT_SECURITY_MEDIUM;
1554 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001555 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001556 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001557 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001558
Johan Hedbergba4e5642011-11-11 00:07:34 +02001559 if (cp->addr.type == MGMT_ADDR_BREDR)
1560 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001561 auth_type);
1562 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001563 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001564 auth_type);
1565
Johan Hedberg1425acb2011-11-11 00:07:35 +02001566 memset(&rp, 0, sizeof(rp));
1567 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1568 rp.addr.type = cp->addr.type;
1569
Ville Tervo30e76272011-02-22 16:10:53 -03001570 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001571 rp.status = -PTR_ERR(conn);
1572 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1573 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001574 goto unlock;
1575 }
1576
1577 if (conn->connect_cfm_cb) {
1578 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001579 rp.status = EBUSY;
1580 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1581 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001582 goto unlock;
1583 }
1584
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001585 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001586 if (!cmd) {
1587 err = -ENOMEM;
1588 hci_conn_put(conn);
1589 goto unlock;
1590 }
1591
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001592 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001593 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001594 conn->connect_cfm_cb = pairing_complete_cb;
1595
Johan Hedberge9a416b2011-02-19 12:05:56 -03001596 conn->security_cfm_cb = pairing_complete_cb;
1597 conn->disconn_cfm_cb = pairing_complete_cb;
1598 conn->io_capability = cp->io_cap;
1599 cmd->user_data = conn;
1600
1601 if (conn->state == BT_CONNECTED &&
1602 hci_conn_security(conn, sec_level, auth_type))
1603 pairing_complete(cmd, 0);
1604
1605 err = 0;
1606
1607unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001608 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001609 hci_dev_put(hdev);
1610
1611 return err;
1612}
1613
Brian Gix0df4c182011-11-16 13:53:13 -08001614static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1615 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001616{
Johan Hedberga5c29682011-02-19 12:05:57 -03001617 struct pending_cmd *cmd;
1618 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001619 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001620 int err;
1621
Szymon Janc4e51eae2011-02-25 19:05:48 +01001622 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001623 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001624 return cmd_status(sk, index, mgmt_op,
1625 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001626
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001627 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001628
Johan Hedberga5c29682011-02-19 12:05:57 -03001629 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001630 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1631 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001632 }
1633
Brian Gix47c15e22011-11-16 13:53:14 -08001634 /*
1635 * Check for an existing ACL link, if present pair via
1636 * HCI commands.
1637 *
1638 * If no ACL link is present, check for an LE link and if
1639 * present, pair via the SMP engine.
1640 *
1641 * If neither ACL nor LE links are present, fail with error.
1642 */
1643 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1644 if (!conn) {
1645 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1646 if (!conn) {
1647 err = cmd_status(sk, index, mgmt_op,
1648 MGMT_STATUS_NOT_CONNECTED);
1649 goto done;
1650 }
1651
1652 /* Continue with pairing via SMP */
1653
1654 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
1655 goto done;
1656 }
1657
Brian Gix0df4c182011-11-16 13:53:13 -08001658 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001659 if (!cmd) {
1660 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001661 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001662 }
1663
Brian Gix0df4c182011-11-16 13:53:13 -08001664 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001665 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1666 struct hci_cp_user_passkey_reply cp;
1667
1668 bacpy(&cp.bdaddr, bdaddr);
1669 cp.passkey = passkey;
1670 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1671 } else
1672 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1673
Johan Hedberga664b5b2011-02-19 12:06:02 -03001674 if (err < 0)
1675 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001676
Brian Gix0df4c182011-11-16 13:53:13 -08001677done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001678 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001679 hci_dev_put(hdev);
1680
1681 return err;
1682}
1683
Brian Gix0df4c182011-11-16 13:53:13 -08001684static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1685{
1686 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1687
1688 BT_DBG("");
1689
1690 if (len != sizeof(*cp))
1691 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1692 MGMT_STATUS_INVALID_PARAMS);
1693
1694 return user_pairing_resp(sk, index, &cp->bdaddr,
1695 MGMT_OP_USER_CONFIRM_REPLY,
1696 HCI_OP_USER_CONFIRM_REPLY, 0);
1697}
1698
1699static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1700 u16 len)
1701{
1702 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1703
1704 BT_DBG("");
1705
1706 if (len != sizeof(*cp))
1707 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1708 MGMT_STATUS_INVALID_PARAMS);
1709
1710 return user_pairing_resp(sk, index, &cp->bdaddr,
1711 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1712 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1713}
1714
Brian Gix604086b2011-11-23 08:28:33 -08001715static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1716{
1717 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1718
1719 BT_DBG("");
1720
1721 if (len != sizeof(*cp))
1722 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1723 EINVAL);
1724
1725 return user_pairing_resp(sk, index, &cp->bdaddr,
1726 MGMT_OP_USER_PASSKEY_REPLY,
1727 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1728}
1729
1730static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1731 u16 len)
1732{
1733 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1734
1735 BT_DBG("");
1736
1737 if (len != sizeof(*cp))
1738 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1739 EINVAL);
1740
1741 return user_pairing_resp(sk, index, &cp->bdaddr,
1742 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1743 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1744}
1745
Johan Hedbergb312b1612011-03-16 14:29:37 +02001746static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1747 u16 len)
1748{
1749 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1750 struct hci_cp_write_local_name hci_cp;
1751 struct hci_dev *hdev;
1752 struct pending_cmd *cmd;
1753 int err;
1754
1755 BT_DBG("");
1756
1757 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001758 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1759 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001760
1761 hdev = hci_dev_get(index);
1762 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001763 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1764 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001765
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001766 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001767
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001768 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001769 if (!cmd) {
1770 err = -ENOMEM;
1771 goto failed;
1772 }
1773
1774 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1775 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1776 &hci_cp);
1777 if (err < 0)
1778 mgmt_pending_remove(cmd);
1779
1780failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001781 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001782 hci_dev_put(hdev);
1783
1784 return err;
1785}
1786
Szymon Jancc35938b2011-03-22 13:12:21 +01001787static int read_local_oob_data(struct sock *sk, u16 index)
1788{
1789 struct hci_dev *hdev;
1790 struct pending_cmd *cmd;
1791 int err;
1792
1793 BT_DBG("hci%u", index);
1794
1795 hdev = hci_dev_get(index);
1796 if (!hdev)
1797 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001798 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001799
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001800 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001801
1802 if (!test_bit(HCI_UP, &hdev->flags)) {
1803 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001804 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001805 goto unlock;
1806 }
1807
1808 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1809 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001810 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001811 goto unlock;
1812 }
1813
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001814 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001815 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1816 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001817 goto unlock;
1818 }
1819
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001820 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001821 if (!cmd) {
1822 err = -ENOMEM;
1823 goto unlock;
1824 }
1825
1826 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1827 if (err < 0)
1828 mgmt_pending_remove(cmd);
1829
1830unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001831 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001832 hci_dev_put(hdev);
1833
1834 return err;
1835}
1836
Szymon Janc2763eda2011-03-22 13:12:22 +01001837static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1838 u16 len)
1839{
1840 struct hci_dev *hdev;
1841 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1842 int err;
1843
1844 BT_DBG("hci%u ", index);
1845
1846 if (len != sizeof(*cp))
1847 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001848 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001849
1850 hdev = hci_dev_get(index);
1851 if (!hdev)
1852 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001853 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001854
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001856
1857 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1858 cp->randomizer);
1859 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001860 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1861 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001862 else
1863 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1864 0);
1865
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001866 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001867 hci_dev_put(hdev);
1868
1869 return err;
1870}
1871
1872static int remove_remote_oob_data(struct sock *sk, u16 index,
1873 unsigned char *data, u16 len)
1874{
1875 struct hci_dev *hdev;
1876 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1877 int err;
1878
1879 BT_DBG("hci%u ", index);
1880
1881 if (len != sizeof(*cp))
1882 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001883 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001884
1885 hdev = hci_dev_get(index);
1886 if (!hdev)
1887 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001888 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001890 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001891
1892 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1893 if (err < 0)
1894 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001895 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001896 else
1897 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1898 NULL, 0);
1899
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001900 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001901 hci_dev_put(hdev);
1902
1903 return err;
1904}
1905
Johan Hedberg450dfda2011-11-12 11:58:22 +02001906static int start_discovery(struct sock *sk, u16 index,
1907 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001908{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001909 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001910 struct pending_cmd *cmd;
1911 struct hci_dev *hdev;
1912 int err;
1913
1914 BT_DBG("hci%u", index);
1915
Johan Hedberg450dfda2011-11-12 11:58:22 +02001916 if (len != sizeof(*cp))
1917 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1918 MGMT_STATUS_INVALID_PARAMS);
1919
Johan Hedberg14a53662011-04-27 10:29:56 -04001920 hdev = hci_dev_get(index);
1921 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001922 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1923 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001924
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001925 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001926
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001927 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001928 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1929 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001930 goto failed;
1931 }
1932
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001933 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001934 if (!cmd) {
1935 err = -ENOMEM;
1936 goto failed;
1937 }
1938
Andre Guedes2519a1f2011-11-07 11:45:24 -03001939 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001940 if (err < 0)
1941 mgmt_pending_remove(cmd);
1942
1943failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001944 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001945 hci_dev_put(hdev);
1946
1947 return err;
1948}
1949
1950static int stop_discovery(struct sock *sk, u16 index)
1951{
1952 struct hci_dev *hdev;
1953 struct pending_cmd *cmd;
1954 int err;
1955
1956 BT_DBG("hci%u", index);
1957
1958 hdev = hci_dev_get(index);
1959 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001960 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1961 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001962
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001963 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001964
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001965 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001966 if (!cmd) {
1967 err = -ENOMEM;
1968 goto failed;
1969 }
1970
Andre Guedes023d50492011-11-04 14:16:52 -03001971 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001972 if (err < 0)
1973 mgmt_pending_remove(cmd);
1974
1975failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001976 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001977 hci_dev_put(hdev);
1978
1979 return err;
1980}
1981
Antti Julku7fbec222011-06-15 12:01:15 +03001982static int block_device(struct sock *sk, u16 index, unsigned char *data,
1983 u16 len)
1984{
1985 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001986 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001987 int err;
1988
1989 BT_DBG("hci%u", index);
1990
Antti Julku7fbec222011-06-15 12:01:15 +03001991 if (len != sizeof(*cp))
1992 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001993 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001994
1995 hdev = hci_dev_get(index);
1996 if (!hdev)
1997 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001998 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001999
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002000 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002001
Antti Julku7fbec222011-06-15 12:01:15 +03002002 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03002003 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002004 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2005 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002006 else
2007 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2008 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002009
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002010 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002011 hci_dev_put(hdev);
2012
2013 return err;
2014}
2015
2016static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
2017 u16 len)
2018{
2019 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03002020 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03002021 int err;
2022
2023 BT_DBG("hci%u", index);
2024
Antti Julku7fbec222011-06-15 12:01:15 +03002025 if (len != sizeof(*cp))
2026 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002027 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002028
2029 hdev = hci_dev_get(index);
2030 if (!hdev)
2031 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002032 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002034 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002035
Antti Julku7fbec222011-06-15 12:01:15 +03002036 err = hci_blacklist_del(hdev, &cp->bdaddr);
2037
2038 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002039 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2040 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002041 else
2042 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2043 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002044
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002045 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002046 hci_dev_put(hdev);
2047
2048 return err;
2049}
2050
Antti Julkuf6422ec2011-06-22 13:11:56 +03002051static int set_fast_connectable(struct sock *sk, u16 index,
2052 unsigned char *data, u16 len)
2053{
2054 struct hci_dev *hdev;
2055 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
2056 struct hci_cp_write_page_scan_activity acp;
2057 u8 type;
2058 int err;
2059
2060 BT_DBG("hci%u", index);
2061
2062 if (len != sizeof(*cp))
2063 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002064 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002065
2066 hdev = hci_dev_get(index);
2067 if (!hdev)
2068 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002069 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002070
2071 hci_dev_lock(hdev);
2072
2073 if (cp->enable) {
2074 type = PAGE_SCAN_TYPE_INTERLACED;
2075 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2076 } else {
2077 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2078 acp.interval = 0x0800; /* default 1.28 sec page scan */
2079 }
2080
2081 acp.window = 0x0012; /* default 11.25 msec page scan window */
2082
2083 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2084 sizeof(acp), &acp);
2085 if (err < 0) {
2086 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002087 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002088 goto done;
2089 }
2090
2091 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2092 if (err < 0) {
2093 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002094 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002095 goto done;
2096 }
2097
2098 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2099 NULL, 0);
2100done:
2101 hci_dev_unlock(hdev);
2102 hci_dev_put(hdev);
2103
2104 return err;
2105}
2106
Johan Hedberg03811012010-12-08 00:21:06 +02002107int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2108{
2109 unsigned char *buf;
2110 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002111 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002112 int err;
2113
2114 BT_DBG("got %zu bytes", msglen);
2115
2116 if (msglen < sizeof(*hdr))
2117 return -EINVAL;
2118
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002119 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002120 if (!buf)
2121 return -ENOMEM;
2122
2123 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2124 err = -EFAULT;
2125 goto done;
2126 }
2127
2128 hdr = (struct mgmt_hdr *) buf;
2129 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002130 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002131 len = get_unaligned_le16(&hdr->len);
2132
2133 if (len != msglen - sizeof(*hdr)) {
2134 err = -EINVAL;
2135 goto done;
2136 }
2137
2138 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002139 case MGMT_OP_READ_VERSION:
2140 err = read_version(sk);
2141 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002142 case MGMT_OP_READ_INDEX_LIST:
2143 err = read_index_list(sk);
2144 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002145 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002146 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002147 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002148 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002149 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002150 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002151 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002152 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002153 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002154 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002155 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002156 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002157 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002158 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002159 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002160 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002161 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002162 break;
2163 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002164 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002165 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002166 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002167 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002168 break;
2169 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002170 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002171 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002172 case MGMT_OP_LOAD_LINK_KEYS:
2173 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002174 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002175 case MGMT_OP_REMOVE_KEYS:
2176 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002177 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002178 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002179 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002180 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002181 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002182 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002183 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002184 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002185 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002186 break;
2187 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002188 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002189 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002190 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002191 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002192 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002193 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002194 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002195 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002196 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002197 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002198 break;
2199 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002200 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2201 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002202 break;
Brian Gix604086b2011-11-23 08:28:33 -08002203 case MGMT_OP_USER_PASSKEY_REPLY:
2204 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2205 break;
2206 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2207 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2208 len);
2209 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002210 case MGMT_OP_SET_LOCAL_NAME:
2211 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2212 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002213 case MGMT_OP_READ_LOCAL_OOB_DATA:
2214 err = read_local_oob_data(sk, index);
2215 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002216 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2217 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2218 break;
2219 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2220 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2221 len);
2222 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002223 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002224 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002225 break;
2226 case MGMT_OP_STOP_DISCOVERY:
2227 err = stop_discovery(sk, index);
2228 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002229 case MGMT_OP_BLOCK_DEVICE:
2230 err = block_device(sk, index, buf + sizeof(*hdr), len);
2231 break;
2232 case MGMT_OP_UNBLOCK_DEVICE:
2233 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2234 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002235 case MGMT_OP_SET_FAST_CONNECTABLE:
2236 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2237 len);
2238 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002239 default:
2240 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002241 err = cmd_status(sk, index, opcode,
2242 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg03811012010-12-08 00:21:06 +02002243 break;
2244 }
2245
Johan Hedberge41d8b42010-12-13 21:07:03 +02002246 if (err < 0)
2247 goto done;
2248
Johan Hedberg03811012010-12-08 00:21:06 +02002249 err = msglen;
2250
2251done:
2252 kfree(buf);
2253 return err;
2254}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002255
Johan Hedbergb24752f2011-11-03 14:40:33 +02002256static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2257{
2258 u8 *status = data;
2259
2260 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2261 mgmt_pending_remove(cmd);
2262}
2263
Johan Hedberg744cf192011-11-08 20:40:14 +02002264int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002265{
Johan Hedberg744cf192011-11-08 20:40:14 +02002266 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002267}
2268
Johan Hedberg744cf192011-11-08 20:40:14 +02002269int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002270{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002271 u8 status = ENODEV;
2272
Johan Hedberg744cf192011-11-08 20:40:14 +02002273 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002274
Johan Hedberg744cf192011-11-08 20:40:14 +02002275 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002276}
2277
Johan Hedberg73f22f62010-12-29 16:00:25 +02002278struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002279 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002280 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002281 struct hci_dev *hdev;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002282};
2283
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002284static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002285{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002286 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002287
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002288 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002289
2290 list_del(&cmd->list);
2291
2292 if (match->sk == NULL) {
2293 match->sk = cmd->sk;
2294 sock_hold(match->sk);
2295 }
2296
2297 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002298}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002299
Johan Hedberg744cf192011-11-08 20:40:14 +02002300int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002301{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002302 struct cmd_lookup match = { powered, NULL, hdev };
2303 __le32 ev;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002304 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002305
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002306 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002307
Johan Hedbergb24752f2011-11-03 14:40:33 +02002308 if (!powered) {
2309 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002310 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002311 }
2312
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002313 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002314
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002315 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2316 match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002317
2318 if (match.sk)
2319 sock_put(match.sk);
2320
2321 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002322}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002323
Johan Hedberg744cf192011-11-08 20:40:14 +02002324int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002325{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002326 struct cmd_lookup match = { discoverable, NULL, hdev };
2327 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002328 int ret;
2329
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002330 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002331
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002332 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg73f22f62010-12-29 16:00:25 +02002333
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002334 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002335 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002336 if (match.sk)
2337 sock_put(match.sk);
2338
2339 return ret;
2340}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002341
Johan Hedberg744cf192011-11-08 20:40:14 +02002342int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002343{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002344 __le32 ev;
2345 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002346 int ret;
2347
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002348 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2349 &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002350
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002351 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002352
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002353 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002354
2355 if (match.sk)
2356 sock_put(match.sk);
2357
2358 return ret;
2359}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002360
Johan Hedberg744cf192011-11-08 20:40:14 +02002361int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002362{
Johan Hedbergca69b792011-11-11 18:10:00 +02002363 u8 mgmt_err = mgmt_status(status);
2364
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002365 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002366 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002367 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002368
2369 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002370 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002371 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002372
2373 return 0;
2374}
2375
Johan Hedberg744cf192011-11-08 20:40:14 +02002376int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2377 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002378{
Johan Hedberg86742e12011-11-07 23:13:38 +02002379 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002380
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002381 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002382
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002383 ev.store_hint = persistent;
2384 bacpy(&ev.key.bdaddr, &key->bdaddr);
2385 ev.key.type = key->type;
2386 memcpy(ev.key.val, key->val, 16);
2387 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002388
Johan Hedberg744cf192011-11-08 20:40:14 +02002389 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002390}
Johan Hedbergf7520542011-01-20 12:34:39 +02002391
Johan Hedberg48264f02011-11-09 13:58:58 +02002392int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2393 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002394{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002395 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002396
Johan Hedbergf7520542011-01-20 12:34:39 +02002397 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002398 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002399
Johan Hedberg744cf192011-11-08 20:40:14 +02002400 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002401}
2402
Johan Hedberg8962ee72011-01-20 12:40:27 +02002403static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2404{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002405 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002406 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002407 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002408
Johan Hedberga38528f2011-01-22 06:46:43 +02002409 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002410 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002411
Szymon Janc4e51eae2011-02-25 19:05:48 +01002412 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002413
2414 *sk = cmd->sk;
2415 sock_hold(*sk);
2416
Johan Hedberga664b5b2011-02-19 12:06:02 -03002417 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418}
2419
Johan Hedberga8a1d192011-11-10 15:54:38 +02002420static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2421{
2422 u8 *status = data;
2423 struct mgmt_cp_remove_keys *cp = cmd->param;
2424 struct mgmt_rp_remove_keys rp;
2425
2426 memset(&rp, 0, sizeof(rp));
2427 bacpy(&rp.bdaddr, &cp->bdaddr);
2428 if (status != NULL)
2429 rp.status = *status;
2430
2431 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2432 sizeof(rp));
2433
2434 mgmt_pending_remove(cmd);
2435}
2436
Johan Hedberg48264f02011-11-09 13:58:58 +02002437int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2438 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002439{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002440 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002441 struct sock *sk = NULL;
2442 int err;
2443
Johan Hedberg744cf192011-11-08 20:40:14 +02002444 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002445
Johan Hedbergf7520542011-01-20 12:34:39 +02002446 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002447 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002448
Johan Hedberg744cf192011-11-08 20:40:14 +02002449 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002450
2451 if (sk)
2452 sock_put(sk);
2453
Johan Hedberga8a1d192011-11-10 15:54:38 +02002454 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2455
Johan Hedberg8962ee72011-01-20 12:40:27 +02002456 return err;
2457}
2458
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002459int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002460{
2461 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002462 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002463 int err;
2464
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002465 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002466 if (!cmd)
2467 return -ENOENT;
2468
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002469 if (bdaddr) {
2470 struct mgmt_rp_disconnect rp;
2471
2472 bacpy(&rp.bdaddr, bdaddr);
2473 rp.status = status;
2474
2475 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2476 &rp, sizeof(rp));
2477 } else
2478 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002479 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002480
Johan Hedberga664b5b2011-02-19 12:06:02 -03002481 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002482
2483 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002484}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002485
Johan Hedberg48264f02011-11-09 13:58:58 +02002486int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2487 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002488{
2489 struct mgmt_ev_connect_failed ev;
2490
Johan Hedberg4c659c32011-11-07 23:13:39 +02002491 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002492 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002493 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002494
Johan Hedberg744cf192011-11-08 20:40:14 +02002495 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002496}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002497
Johan Hedberg744cf192011-11-08 20:40:14 +02002498int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002499{
2500 struct mgmt_ev_pin_code_request ev;
2501
Johan Hedberg980e1a52011-01-22 06:10:07 +02002502 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002503 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002504
Johan Hedberg744cf192011-11-08 20:40:14 +02002505 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002506 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002507}
2508
Johan Hedberg744cf192011-11-08 20:40:14 +02002509int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2510 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002511{
2512 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002513 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002514 int err;
2515
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002516 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002517 if (!cmd)
2518 return -ENOENT;
2519
Johan Hedbergac56fb12011-02-19 12:05:59 -03002520 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002521 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002522
Johan Hedberg744cf192011-11-08 20:40:14 +02002523 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002524 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002525
Johan Hedberga664b5b2011-02-19 12:06:02 -03002526 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002527
2528 return err;
2529}
2530
Johan Hedberg744cf192011-11-08 20:40:14 +02002531int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2532 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002533{
2534 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002535 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002536 int err;
2537
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002538 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002539 if (!cmd)
2540 return -ENOENT;
2541
Johan Hedbergac56fb12011-02-19 12:05:59 -03002542 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002543 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002544
Johan Hedberg744cf192011-11-08 20:40:14 +02002545 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002546 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002547
Johan Hedberga664b5b2011-02-19 12:06:02 -03002548 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002549
2550 return err;
2551}
Johan Hedberga5c29682011-02-19 12:05:57 -03002552
Johan Hedberg744cf192011-11-08 20:40:14 +02002553int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2554 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002555{
2556 struct mgmt_ev_user_confirm_request ev;
2557
Johan Hedberg744cf192011-11-08 20:40:14 +02002558 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002559
Johan Hedberga5c29682011-02-19 12:05:57 -03002560 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002561 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002562 put_unaligned_le32(value, &ev.value);
2563
Johan Hedberg744cf192011-11-08 20:40:14 +02002564 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002565 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002566}
2567
Brian Gix604086b2011-11-23 08:28:33 -08002568int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2569{
2570 struct mgmt_ev_user_passkey_request ev;
2571
2572 BT_DBG("%s", hdev->name);
2573
2574 bacpy(&ev.bdaddr, bdaddr);
2575
2576 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2577 NULL);
2578}
2579
Brian Gix0df4c182011-11-16 13:53:13 -08002580static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002581 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002582{
2583 struct pending_cmd *cmd;
2584 struct mgmt_rp_user_confirm_reply rp;
2585 int err;
2586
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002587 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002588 if (!cmd)
2589 return -ENOENT;
2590
Johan Hedberga5c29682011-02-19 12:05:57 -03002591 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002592 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002593 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002594
Johan Hedberga664b5b2011-02-19 12:06:02 -03002595 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002596
2597 return err;
2598}
2599
Johan Hedberg744cf192011-11-08 20:40:14 +02002600int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2601 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002602{
Brian Gix0df4c182011-11-16 13:53:13 -08002603 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002604 MGMT_OP_USER_CONFIRM_REPLY);
2605}
2606
Johan Hedberg744cf192011-11-08 20:40:14 +02002607int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2608 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002609{
Brian Gix0df4c182011-11-16 13:53:13 -08002610 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002611 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2612}
Johan Hedberg2a611692011-02-19 12:06:00 -03002613
Brian Gix604086b2011-11-23 08:28:33 -08002614int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2615 u8 status)
2616{
2617 return user_pairing_resp_complete(hdev, bdaddr, status,
2618 MGMT_OP_USER_PASSKEY_REPLY);
2619}
2620
2621int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2622 bdaddr_t *bdaddr, u8 status)
2623{
2624 return user_pairing_resp_complete(hdev, bdaddr, status,
2625 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2626}
2627
Johan Hedberg744cf192011-11-08 20:40:14 +02002628int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002629{
2630 struct mgmt_ev_auth_failed ev;
2631
Johan Hedberg2a611692011-02-19 12:06:00 -03002632 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002633 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002634
Johan Hedberg744cf192011-11-08 20:40:14 +02002635 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002636}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002637
Johan Hedberg744cf192011-11-08 20:40:14 +02002638int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002639{
2640 struct pending_cmd *cmd;
2641 struct mgmt_cp_set_local_name ev;
2642 int err;
2643
2644 memset(&ev, 0, sizeof(ev));
2645 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2646
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002647 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002648 if (!cmd)
2649 goto send_event;
2650
2651 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002652 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002653 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002654 goto failed;
2655 }
2656
Johan Hedberg744cf192011-11-08 20:40:14 +02002657 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002658
Johan Hedberg744cf192011-11-08 20:40:14 +02002659 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002660 sizeof(ev));
2661 if (err < 0)
2662 goto failed;
2663
2664send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002665 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002666 cmd ? cmd->sk : NULL);
2667
2668failed:
2669 if (cmd)
2670 mgmt_pending_remove(cmd);
2671 return err;
2672}
Szymon Jancc35938b2011-03-22 13:12:21 +01002673
Johan Hedberg744cf192011-11-08 20:40:14 +02002674int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2675 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002676{
2677 struct pending_cmd *cmd;
2678 int err;
2679
Johan Hedberg744cf192011-11-08 20:40:14 +02002680 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002681
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002682 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002683 if (!cmd)
2684 return -ENOENT;
2685
2686 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002687 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002688 MGMT_OP_READ_LOCAL_OOB_DATA,
2689 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002690 } else {
2691 struct mgmt_rp_read_local_oob_data rp;
2692
2693 memcpy(rp.hash, hash, sizeof(rp.hash));
2694 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2695
Johan Hedberg744cf192011-11-08 20:40:14 +02002696 err = cmd_complete(cmd->sk, hdev->id,
2697 MGMT_OP_READ_LOCAL_OOB_DATA,
2698 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002699 }
2700
2701 mgmt_pending_remove(cmd);
2702
2703 return err;
2704}
Johan Hedberge17acd42011-03-30 23:57:16 +03002705
Johan Hedberg48264f02011-11-09 13:58:58 +02002706int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2707 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002708{
2709 struct mgmt_ev_device_found ev;
2710
2711 memset(&ev, 0, sizeof(ev));
2712
Johan Hedberg4c659c32011-11-07 23:13:39 +02002713 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002714 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002715 ev.rssi = rssi;
2716
2717 if (eir)
2718 memcpy(ev.eir, eir, sizeof(ev.eir));
2719
Andre Guedesf8523592011-09-09 18:56:26 -03002720 if (dev_class)
2721 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2722
Johan Hedberg744cf192011-11-08 20:40:14 +02002723 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002724}
Johan Hedberga88a9652011-03-30 13:18:12 +03002725
Johan Hedberg744cf192011-11-08 20:40:14 +02002726int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002727{
2728 struct mgmt_ev_remote_name ev;
2729
2730 memset(&ev, 0, sizeof(ev));
2731
2732 bacpy(&ev.bdaddr, bdaddr);
2733 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2734
Johan Hedberg744cf192011-11-08 20:40:14 +02002735 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002736}
Johan Hedberg314b2382011-04-27 10:29:57 -04002737
Andre Guedes7a135102011-11-09 17:14:25 -03002738int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002739{
2740 struct pending_cmd *cmd;
2741 int err;
2742
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002743 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002744 if (!cmd)
2745 return -ENOENT;
2746
Johan Hedbergca69b792011-11-11 18:10:00 +02002747 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002748 mgmt_pending_remove(cmd);
2749
2750 return err;
2751}
2752
Andre Guedese6d465c2011-11-09 17:14:26 -03002753int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2754{
2755 struct pending_cmd *cmd;
2756 int err;
2757
2758 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2759 if (!cmd)
2760 return -ENOENT;
2761
2762 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2763 mgmt_pending_remove(cmd);
2764
2765 return err;
2766}
2767
Johan Hedberg744cf192011-11-08 20:40:14 +02002768int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002769{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002770 struct pending_cmd *cmd;
2771
2772 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002773 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002774 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002775 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002776
2777 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002778 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002779 mgmt_pending_remove(cmd);
2780 }
2781
Johan Hedberg744cf192011-11-08 20:40:14 +02002782 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002783 sizeof(discovering), NULL);
2784}
Antti Julku5e762442011-08-25 16:48:02 +03002785
Johan Hedberg744cf192011-11-08 20:40:14 +02002786int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002787{
2788 struct pending_cmd *cmd;
2789 struct mgmt_ev_device_blocked ev;
2790
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002791 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002792
2793 bacpy(&ev.bdaddr, bdaddr);
2794
Johan Hedberg744cf192011-11-08 20:40:14 +02002795 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2796 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002797}
2798
Johan Hedberg744cf192011-11-08 20:40:14 +02002799int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002800{
2801 struct pending_cmd *cmd;
2802 struct mgmt_ev_device_unblocked ev;
2803
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002804 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002805
2806 bacpy(&ev.bdaddr, bdaddr);
2807
Johan Hedberg744cf192011-11-08 20:40:14 +02002808 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2809 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002810}