blob: fb85c02a0ecbbd43d1b89428b8f1ab826b7be782 [file] [log] [blame]
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +09001/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07002 BlueZ - Bluetooth protocol stack for Linux
Brian Gix3cd62042012-01-11 15:18:17 -08003 Copyright (c) 2000-2001, 2010-2012 Code Aurora Forum. All rights reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004
5 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090015 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Linus Torvalds1da177e2005-04-16 15:20:36 -070018 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +090020 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
Linus Torvalds1da177e2005-04-16 15:20:36 -070022 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI connection handling. */
26
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include <linux/module.h>
28
29#include <linux/types.h>
30#include <linux/errno.h>
31#include <linux/kernel.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include <linux/slab.h>
33#include <linux/poll.h>
34#include <linux/fcntl.h>
35#include <linux/init.h>
36#include <linux/skbuff.h>
37#include <linux/interrupt.h>
38#include <linux/notifier.h>
39#include <net/sock.h>
40
41#include <asm/system.h>
Andrei Emeltchenko70f230202010-12-01 16:58:25 +020042#include <linux/uaccess.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include <asm/unaligned.h>
44
45#include <net/bluetooth/bluetooth.h>
46#include <net/bluetooth/hci_core.h>
Brian Gixa94b6122012-02-23 16:07:10 -080047#include <net/bluetooth/l2cap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Brian Gixa94b6122012-02-23 16:07:10 -080049struct hci_conn *hci_le_connect(struct hci_dev *hdev, __u16 pkt_type,
50 bdaddr_t *dst, __u8 sec_level, __u8 auth_type,
51 struct bt_le_params *le_params)
Ville Tervofcd89c02011-02-10 22:38:47 -030052{
Sunny Kapdi93bef892012-07-30 14:52:56 -070053 struct hci_conn *le, *le_wlist_conn;
Ville Tervofcd89c02011-02-10 22:38:47 -030054 struct hci_cp_le_create_conn cp;
Brian Gixa94b6122012-02-23 16:07:10 -080055 struct adv_entry *entry;
56 struct link_key *key;
Ville Tervofcd89c02011-02-10 22:38:47 -030057
Brian Gixa94b6122012-02-23 16:07:10 -080058 BT_DBG("%p", hdev);
Brian Gix114f3a62011-09-27 14:02:20 -070059
Brian Gixa94b6122012-02-23 16:07:10 -080060 le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
61 if (le) {
Sunny Kapdi93bef892012-07-30 14:52:56 -070062 le_wlist_conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
63 BDADDR_ANY);
64 if (!le_wlist_conn) {
65 hci_conn_hold(le);
66 return le;
67 } else {
68 BT_DBG("remove wlist conn");
69 le->out = 1;
70 le->link_mode |= HCI_LM_MASTER;
71 le->sec_level = BT_SECURITY_LOW;
72 le->type = LE_LINK;
73 hci_proto_connect_cfm(le, 0);
74 hci_conn_del(le_wlist_conn);
75 return le;
76 }
Brian Gixa94b6122012-02-23 16:07:10 -080077 }
78
79 key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
80 if (!key) {
81 entry = hci_find_adv_entry(hdev, dst);
82 if (entry)
83 le = hci_le_conn_add(hdev, dst,
84 entry->bdaddr_type);
85 else
86 le = hci_le_conn_add(hdev, dst, 0);
87 } else {
88 le = hci_le_conn_add(hdev, dst, key->addr_type);
89 }
90
91 if (!le)
92 return ERR_PTR(-ENOMEM);
93
94 hci_conn_hold(le);
95
96 le->state = BT_CONNECT;
97 le->out = 1;
98 le->link_mode |= HCI_LM_MASTER;
99 le->sec_level = BT_SECURITY_LOW;
100 le->type = LE_LINK;
Ville Tervofcd89c02011-02-10 22:38:47 -0300101
102 memset(&cp, 0, sizeof(cp));
Brian Gixa94b6122012-02-23 16:07:10 -0800103 if (l2cap_sock_le_params_valid(le_params)) {
104 cp.supervision_timeout =
105 cpu_to_le16(le_params->supervision_timeout);
106 cp.scan_interval = cpu_to_le16(le_params->scan_interval);
107 cp.scan_window = cpu_to_le16(le_params->scan_window);
108 cp.conn_interval_min = cpu_to_le16(le_params->interval_min);
109 cp.conn_interval_max = cpu_to_le16(le_params->interval_max);
110 cp.conn_latency = cpu_to_le16(le_params->latency);
111 cp.min_ce_len = cpu_to_le16(le_params->min_ce_len);
112 cp.max_ce_len = cpu_to_le16(le_params->max_ce_len);
113 le->conn_timeout = le_params->conn_timeout;
114 } else {
115 cp.supervision_timeout = cpu_to_le16(BT_LE_SUP_TO_DEFAULT);
116 cp.scan_interval = cpu_to_le16(BT_LE_SCAN_INTERVAL_DEF);
117 cp.scan_window = cpu_to_le16(BT_LE_SCAN_WINDOW_DEF);
118 cp.conn_interval_min = cpu_to_le16(BT_LE_CONN_INTERVAL_MIN_DEF);
119 cp.conn_interval_max = cpu_to_le16(BT_LE_CONN_INTERVAL_MAX_DEF);
120 cp.conn_latency = cpu_to_le16(BT_LE_LATENCY_DEF);
121 le->conn_timeout = 5;
122 }
Sunny Kapdi93bef892012-07-30 14:52:56 -0700123 if (!bacmp(&le->dst, BDADDR_ANY)) {
124 cp.filter_policy = 0x01;
125 le->conn_timeout = 0;
126 } else {
127 bacpy(&cp.peer_addr, &le->dst);
128 cp.peer_addr_type = le->dst_type;
129 }
Ville Tervofcd89c02011-02-10 22:38:47 -0300130
131 hci_send_cmd(hdev, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp);
Brian Gixa94b6122012-02-23 16:07:10 -0800132
133 return le;
Ville Tervofcd89c02011-02-10 22:38:47 -0300134}
Brian Gixa94b6122012-02-23 16:07:10 -0800135EXPORT_SYMBOL(hci_le_connect);
Ville Tervofcd89c02011-02-10 22:38:47 -0300136
137static void hci_le_connect_cancel(struct hci_conn *conn)
138{
139 hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL);
140}
141
Sunny Kapdi93bef892012-07-30 14:52:56 -0700142void hci_le_cancel_create_connect(struct hci_dev *hdev, bdaddr_t *dst)
143{
144 struct hci_conn *le;
145
146 BT_DBG("%p", hdev);
147
148 le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
149 if (le) {
150 BT_DBG("send hci connect cancel");
151 hci_le_connect_cancel(le);
152 hci_conn_del(le);
153 }
154}
155EXPORT_SYMBOL(hci_le_cancel_create_connect);
156
157void hci_le_add_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst)
158{
159 struct hci_cp_le_add_dev_white_list cp;
160 struct adv_entry *entry;
161 struct link_key *key;
162
163 BT_DBG("%p", hdev);
164
165 memset(&cp, 0, sizeof(cp));
166 bacpy(&cp.addr, dst);
167
168 key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
169 if (!key) {
170 entry = hci_find_adv_entry(hdev, dst);
171 if (entry)
172 cp.addr_type = entry->bdaddr_type;
173 else
174 cp.addr_type = 0x00;
175 } else {
176 cp.addr_type = key->addr_type;
177 }
178
179 hci_send_cmd(hdev, HCI_OP_LE_ADD_DEV_WHITE_LIST, sizeof(cp), &cp);
180}
181EXPORT_SYMBOL(hci_le_add_dev_white_list);
182
183void hci_le_remove_dev_white_list(struct hci_dev *hdev, bdaddr_t *dst)
184{
185 struct hci_cp_le_remove_dev_white_list cp;
186 struct adv_entry *entry;
187 struct link_key *key;
188
189 BT_DBG("%p", hdev);
190
191 memset(&cp, 0, sizeof(cp));
192 bacpy(&cp.addr, dst);
193
194 key = hci_find_link_key_type(hdev, dst, KEY_TYPE_LTK);
195 if (!key) {
196 entry = hci_find_adv_entry(hdev, dst);
197 if (entry)
198 cp.addr_type = entry->bdaddr_type;
199 else
200 cp.addr_type = 0x00;
201 } else {
202 cp.addr_type = key->addr_type;
203 }
204
205 hci_send_cmd(hdev, HCI_OP_LE_REMOVE_DEV_WHITE_LIST, sizeof(cp), &cp);
206}
207EXPORT_SYMBOL(hci_le_remove_dev_white_list);
208
Mallikarjuna GB0478d652012-08-22 14:18:26 +0530209static inline bool is_role_switch_possible(struct hci_dev *hdev)
210{
211 if (hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECTED))
212 return false;
213 return true;
214}
215
Marcel Holtmann4c67bc72006-10-15 17:30:56 +0200216void hci_acl_connect(struct hci_conn *conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217{
218 struct hci_dev *hdev = conn->hdev;
219 struct inquiry_entry *ie;
220 struct hci_cp_create_conn cp;
221
222 BT_DBG("%p", conn);
223
224 conn->state = BT_CONNECT;
Marcel Holtmanna8746412008-07-14 20:13:46 +0200225 conn->out = 1;
226
Linus Torvalds1da177e2005-04-16 15:20:36 -0700227 conn->link_mode = HCI_LM_MASTER;
228
Marcel Holtmann4c67bc72006-10-15 17:30:56 +0200229 conn->attempt++;
230
Marcel Holtmanne4e8e372008-07-14 20:13:47 +0200231 conn->link_policy = hdev->link_policy;
232
Linus Torvalds1da177e2005-04-16 15:20:36 -0700233 memset(&cp, 0, sizeof(cp));
234 bacpy(&cp.bdaddr, &conn->dst);
235 cp.pscan_rep_mode = 0x02;
236
Andrei Emeltchenko70f230202010-12-01 16:58:25 +0200237 ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
238 if (ie) {
Marcel Holtmann41a96212008-07-14 20:13:48 +0200239 if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
240 cp.pscan_rep_mode = ie->data.pscan_rep_mode;
241 cp.pscan_mode = ie->data.pscan_mode;
242 cp.clock_offset = ie->data.clock_offset |
243 cpu_to_le16(0x8000);
244 }
245
Linus Torvalds1da177e2005-04-16 15:20:36 -0700246 memcpy(conn->dev_class, ie->data.dev_class, 3);
Marcel Holtmann41a96212008-07-14 20:13:48 +0200247 conn->ssp_mode = ie->data.ssp_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 }
249
Marcel Holtmanna8746412008-07-14 20:13:46 +0200250 cp.pkt_type = cpu_to_le16(conn->pkt_type);
Mallikarjuna GB0478d652012-08-22 14:18:26 +0530251 if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER)
252 && is_role_switch_possible(hdev))
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200253 cp.role_switch = 0x01;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700254 else
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200255 cp.role_switch = 0x00;
Marcel Holtmann4c67bc72006-10-15 17:30:56 +0200256
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200257 hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258}
259
Marcel Holtmann6ac59342006-09-26 09:43:48 +0200260static void hci_acl_connect_cancel(struct hci_conn *conn)
261{
262 struct hci_cp_create_conn_cancel cp;
263
264 BT_DBG("%p", conn);
265
266 if (conn->hdev->hci_ver < 2)
267 return;
268
269 bacpy(&cp.bdaddr, &conn->dst);
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200270 hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
Marcel Holtmann6ac59342006-09-26 09:43:48 +0200271}
272
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
274{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 BT_DBG("%p", conn);
276
277 conn->state = BT_DISCONN;
278
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 if (conn->hdev->dev_type == HCI_BREDR) {
280 struct hci_cp_disconnect cp;
281 cp.handle = cpu_to_le16(conn->handle);
282 cp.reason = reason;
283 hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
284 } else {
285 struct hci_cp_disconn_phys_link cp;
286 cp.phy_handle = (u8) conn->handle;
287 cp.reason = reason;
288 hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHYS_LINK,
289 sizeof(cp), &cp);
290 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291}
292
293void hci_add_sco(struct hci_conn *conn, __u16 handle)
294{
295 struct hci_dev *hdev = conn->hdev;
296 struct hci_cp_add_sco cp;
297
298 BT_DBG("%p", conn);
299
300 conn->state = BT_CONNECT;
301 conn->out = 1;
302
Marcel Holtmannefc76882009-02-06 09:13:37 +0100303 conn->attempt++;
304
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -0700305 cp.handle = cpu_to_le16(handle);
Marcel Holtmanna8746412008-07-14 20:13:46 +0200306 cp.pkt_type = cpu_to_le16(conn->pkt_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307
Marcel Holtmanna9de9242007-10-20 13:33:56 +0200308 hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309}
310
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200311void hci_setup_sync(struct hci_conn *conn, __u16 handle)
312{
313 struct hci_dev *hdev = conn->hdev;
314 struct hci_cp_setup_sync_conn cp;
315
316 BT_DBG("%p", conn);
317
318 conn->state = BT_CONNECT;
319 conn->out = 1;
320
Marcel Holtmannefc76882009-02-06 09:13:37 +0100321 conn->attempt++;
322
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200323 cp.handle = cpu_to_le16(handle);
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200324
325 cp.tx_bandwidth = cpu_to_le32(0x00001f40);
326 cp.rx_bandwidth = cpu_to_le32(0x00001f40);
Kun Han Kim15b911f2011-07-08 09:30:28 -0700327 if (conn->hdev->is_wbs) {
328 /* Transparent Data */
329 uint16_t voice_setting = hdev->voice_setting | ACF_TRANS;
330 cp.max_latency = cpu_to_le16(0x000D);
331 cp.pkt_type = cpu_to_le16(ESCO_WBS);
332 cp.voice_setting = cpu_to_le16(voice_setting);
333 /* Retransmission Effort */
334 cp.retrans_effort = RE_LINK_QUALITY;
335 } else {
336 cp.max_latency = cpu_to_le16(0x000A);
337 cp.pkt_type = cpu_to_le16(conn->pkt_type);
338 cp.voice_setting = cpu_to_le16(hdev->voice_setting);
339 cp.retrans_effort = RE_POWER_CONSUMP;
340 }
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200341
342 hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
343}
344
Claudio Takahasi2ce603e2011-02-16 20:44:53 -0200345void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max,
346 u16 latency, u16 to_multiplier)
347{
348 struct hci_cp_le_conn_update cp;
349 struct hci_dev *hdev = conn->hdev;
350
351 memset(&cp, 0, sizeof(cp));
352
353 cp.handle = cpu_to_le16(conn->handle);
354 cp.conn_interval_min = cpu_to_le16(min);
355 cp.conn_interval_max = cpu_to_le16(max);
356 cp.conn_latency = cpu_to_le16(latency);
357 cp.supervision_timeout = cpu_to_le16(to_multiplier);
358 cp.min_ce_len = cpu_to_le16(0x0001);
359 cp.max_ce_len = cpu_to_le16(0x0001);
360
361 hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp);
362}
363EXPORT_SYMBOL(hci_le_conn_update);
364
Archana Ramachandran26a752b2011-12-20 11:27:40 -0800365void hci_read_rssi(struct hci_conn *conn)
366{
367 struct hci_cp_read_rssi cp;
368 struct hci_dev *hdev = conn->hdev;
369
370 memset(&cp, 0, sizeof(cp));
371 cp.handle = cpu_to_le16(conn->handle);
372
373 hci_send_cmd(hdev, HCI_OP_READ_RSSI, sizeof(cp), &cp);
374}
375EXPORT_SYMBOL(hci_read_rssi);
376
Vinicius Costa Gomes735038c2011-06-09 18:50:47 -0300377void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __u8 rand[8],
378 __u8 ltk[16])
379{
380 struct hci_dev *hdev = conn->hdev;
381 struct hci_cp_le_start_enc cp;
382
383 BT_DBG("%p", conn);
384
385 memset(&cp, 0, sizeof(cp));
386
387 cp.handle = cpu_to_le16(conn->handle);
388 memcpy(cp.ltk, ltk, sizeof(cp.ltk));
389 cp.ediv = ediv;
Brian Gix842bc5e2011-09-07 08:13:41 -0700390 memcpy(cp.rand, rand, sizeof(cp.rand));
Vinicius Costa Gomes735038c2011-06-09 18:50:47 -0300391
392 hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);
393}
394EXPORT_SYMBOL(hci_le_start_enc);
395
396void hci_le_ltk_reply(struct hci_conn *conn, u8 ltk[16])
397{
398 struct hci_dev *hdev = conn->hdev;
399 struct hci_cp_le_ltk_reply cp;
400
401 BT_DBG("%p", conn);
402
403 memset(&cp, 0, sizeof(cp));
404
405 cp.handle = cpu_to_le16(conn->handle);
406 memcpy(cp.ltk, ltk, sizeof(ltk));
407
408 hci_send_cmd(hdev, HCI_OP_LE_LTK_REPLY, sizeof(cp), &cp);
409}
410EXPORT_SYMBOL(hci_le_ltk_reply);
411
412void hci_le_ltk_neg_reply(struct hci_conn *conn)
413{
414 struct hci_dev *hdev = conn->hdev;
415 struct hci_cp_le_ltk_neg_reply cp;
416
417 BT_DBG("%p", conn);
418
419 memset(&cp, 0, sizeof(cp));
420
421 cp.handle = cpu_to_le16(conn->handle);
422
423 hci_send_cmd(hdev, HCI_OP_LE_LTK_NEG_REPLY, sizeof(cp), &cp);
424}
425
Marcel Holtmanne73439d2010-07-26 10:06:00 -0400426/* Device _must_ be locked */
427void hci_sco_setup(struct hci_conn *conn, __u8 status)
428{
429 struct hci_conn *sco = conn->link;
430
431 BT_DBG("%p", conn);
432
433 if (!sco)
434 return;
435
436 if (!status) {
437 if (lmp_esco_capable(conn->hdev))
438 hci_setup_sync(sco, conn->handle);
439 else
440 hci_add_sco(sco, conn->handle);
441 } else {
442 hci_proto_connect_cfm(sco, status);
443 hci_conn_del(sco);
444 }
445}
446
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447static void hci_conn_timeout(unsigned long arg)
448{
Marcel Holtmann04837f62006-07-03 10:02:33 +0200449 struct hci_conn *conn = (void *) arg;
450 struct hci_dev *hdev = conn->hdev;
Marcel Holtmann2950f212009-02-12 14:02:50 +0100451 __u8 reason;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700452
453 BT_DBG("conn %p state %d", conn, conn->state);
454
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455 hci_dev_lock(hdev);
Marcel Holtmann6ac59342006-09-26 09:43:48 +0200456
457 switch (conn->state) {
458 case BT_CONNECT:
Marcel Holtmann769be972008-07-14 20:13:49 +0200459 case BT_CONNECT2:
Ville Tervofcd89c02011-02-10 22:38:47 -0300460 if (conn->out) {
461 if (conn->type == ACL_LINK)
462 hci_acl_connect_cancel(conn);
463 else if (conn->type == LE_LINK)
464 hci_le_connect_cancel(conn);
465 }
Marcel Holtmann6ac59342006-09-26 09:43:48 +0200466 break;
Marcel Holtmann769be972008-07-14 20:13:49 +0200467 case BT_CONFIG:
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900468 case BT_CONNECTED:
Brian Gix114f3a62011-09-27 14:02:20 -0700469 if (!atomic_read(&conn->refcnt)) {
470 reason = hci_proto_disconn_ind(conn);
471 hci_acl_disconn(conn, reason);
472 }
Marcel Holtmann6ac59342006-09-26 09:43:48 +0200473 break;
474 default:
Brian Gix114f3a62011-09-27 14:02:20 -0700475 if (!atomic_read(&conn->refcnt))
476 conn->state = BT_CLOSED;
Marcel Holtmann6ac59342006-09-26 09:43:48 +0200477 break;
478 }
479
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 hci_dev_unlock(hdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481}
482
Marcel Holtmann04837f62006-07-03 10:02:33 +0200483static void hci_conn_idle(unsigned long arg)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700484{
Marcel Holtmann04837f62006-07-03 10:02:33 +0200485 struct hci_conn *conn = (void *) arg;
486
487 BT_DBG("conn %p mode %d", conn, conn->mode);
488
489 hci_conn_enter_sniff_mode(conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490}
491
Archana Ramachandran26a752b2011-12-20 11:27:40 -0800492static void hci_conn_rssi_update(struct work_struct *work)
493{
494 struct delayed_work *delayed =
495 container_of(work, struct delayed_work, work);
496 struct hci_conn *conn =
497 container_of(delayed, struct hci_conn, rssi_update_work);
498
499 BT_DBG("conn %p mode %d", conn, conn->mode);
500
501 hci_read_rssi(conn);
502}
503
Prabhakaran Mcafface82012-04-10 11:38:35 +0530504static void encryption_disabled_timeout(unsigned long userdata)
505{
506 struct hci_conn *conn = (struct hci_conn *)userdata;
507 BT_INFO("conn %p Grace Prd Exp ", conn);
508
509 hci_encrypt_cfm(conn, 0, 0);
510
511 if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
512 struct hci_cp_set_conn_encrypt cp;
513 BT_INFO("HCI_CONN_ENCRYPT_PEND is set");
514 cp.handle = cpu_to_le16(conn->handle);
515 cp.encrypt = 1;
516 hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
517 sizeof(cp), &cp);
518 }
519
520}
521
Nick Pellybbcda3b2010-02-11 11:54:28 -0800522struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type,
523 __u16 pkt_type, bdaddr_t *dst)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524{
525 struct hci_conn *conn;
526
527 BT_DBG("%s dst %s", hdev->name, batostr(dst));
528
Marcel Holtmann04837f62006-07-03 10:02:33 +0200529 conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC);
530 if (!conn)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700531 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532
533 bacpy(&conn->dst, dst);
Marcel Holtmanna8746412008-07-14 20:13:46 +0200534 conn->hdev = hdev;
535 conn->type = type;
536 conn->mode = HCI_CM_ACTIVE;
537 conn->state = BT_OPEN;
Andrei Emeltchenko93f19c92009-09-03 12:34:19 +0300538 conn->auth_type = HCI_AT_GENERAL_BONDING;
Johan Hedberg17fa4b92011-01-25 13:28:33 +0200539 conn->io_capability = hdev->io_capability;
Johan Hedberga9583552011-02-19 12:06:01 -0300540 conn->remote_auth = 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700541
Marcel Holtmann04837f62006-07-03 10:02:33 +0200542 conn->power_save = 1;
Marcel Holtmann052b30b2009-04-26 20:01:22 +0200543 conn->disc_timeout = HCI_DISCONN_TIMEOUT;
Srinivas Krovvidi6aadc412012-09-03 18:47:50 +0530544 conn->conn_valid = true;
545 spin_lock_init(&conn->lock);
Rahul Kashyapb44f9e22012-05-03 16:45:17 +0530546 wake_lock_init(&conn->idle_lock, WAKE_LOCK_SUSPEND, "bt_idle");
Marcel Holtmann04837f62006-07-03 10:02:33 +0200547
Marcel Holtmanna8746412008-07-14 20:13:46 +0200548 switch (type) {
549 case ACL_LINK:
550 conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
Rahul Kashyapd5553ba2012-01-02 19:27:19 +0530551 conn->link_policy = hdev->link_policy;
Marcel Holtmanna8746412008-07-14 20:13:46 +0200552 break;
553 case SCO_LINK:
Nick Pellybbcda3b2010-02-11 11:54:28 -0800554 if (!pkt_type)
555 pkt_type = SCO_ESCO_MASK;
Marcel Holtmanna8746412008-07-14 20:13:46 +0200556 case ESCO_LINK:
Nick Pellybbcda3b2010-02-11 11:54:28 -0800557 if (!pkt_type)
558 pkt_type = ALL_ESCO_MASK;
559 if (lmp_esco_capable(hdev)) {
560 /* HCI Setup Synchronous Connection Command uses
561 reverse logic on the EDR_ESCO_MASK bits */
562 conn->pkt_type = (pkt_type ^ EDR_ESCO_MASK) &
563 hdev->esco_type;
564 } else {
565 /* Legacy HCI Add Sco Connection Command uses a
566 shifted bitmask */
567 conn->pkt_type = (pkt_type << 5) & hdev->pkt_type &
568 SCO_PTYPE_MASK;
569 }
Marcel Holtmanna8746412008-07-14 20:13:46 +0200570 break;
571 }
572
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 skb_queue_head_init(&conn->data_q);
Marcel Holtmann04837f62006-07-03 10:02:33 +0200574
Pavel Emelyanovb24b8a22008-01-23 21:20:07 -0800575 setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
576 setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
Archana Ramachandran26a752b2011-12-20 11:27:40 -0800577 INIT_DELAYED_WORK(&conn->rssi_update_work, hci_conn_rssi_update);
Prabhakaran Mcafface82012-04-10 11:38:35 +0530578 setup_timer(&conn->encrypt_pause_timer, encryption_disabled_timeout,
579 (unsigned long)conn);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 atomic_set(&conn->refcnt, 0);
582
583 hci_dev_hold(hdev);
584
585 tasklet_disable(&hdev->tx_task);
586
587 hci_conn_hash_add(hdev, conn);
588 if (hdev->notify)
589 hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
590
Marcel Holtmann9eba32b2009-08-22 14:19:26 -0700591 atomic_set(&conn->devref, 0);
592
Marcel Holtmanna67e8992009-05-02 18:24:06 -0700593 hci_conn_init_sysfs(conn);
594
Linus Torvalds1da177e2005-04-16 15:20:36 -0700595 tasklet_enable(&hdev->tx_task);
596
597 return conn;
598}
599
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600struct hci_conn *hci_le_conn_add(struct hci_dev *hdev, bdaddr_t *dst,
601 __u8 addr_type)
602{
603 struct hci_conn *conn = hci_conn_add(hdev, LE_LINK, 0, dst);
604 if (!conn)
605 return NULL;
606
607 conn->dst_type = addr_type;
608
609 return conn;
610}
611
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612int hci_conn_del(struct hci_conn *conn)
613{
614 struct hci_dev *hdev = conn->hdev;
615
616 BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
617
Srinivas Krovvidi6aadc412012-09-03 18:47:50 +0530618 spin_lock_bh(&conn->lock);
619 conn->conn_valid = false; /* conn data is being released */
620 spin_unlock_bh(&conn->lock);
621
Brian Gix3cd62042012-01-11 15:18:17 -0800622 /* Make sure no timers are running */
Marcel Holtmann04837f62006-07-03 10:02:33 +0200623 del_timer(&conn->idle_timer);
Rahul Kashyapb44f9e22012-05-03 16:45:17 +0530624 wake_lock_destroy(&conn->idle_lock);
Marcel Holtmann04837f62006-07-03 10:02:33 +0200625 del_timer(&conn->disc_timer);
Brian Gix3cd62042012-01-11 15:18:17 -0800626 del_timer(&conn->smp_timer);
Archana Ramachandran26a752b2011-12-20 11:27:40 -0800627 __cancel_delayed_work(&conn->rssi_update_work);
Prabhakaran Mcafface82012-04-10 11:38:35 +0530628 del_timer(&conn->encrypt_pause_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629
Marcel Holtmann5b7f99092007-07-11 09:51:55 +0200630 if (conn->type == ACL_LINK) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631 struct hci_conn *sco = conn->link;
632 if (sco)
633 sco->link = NULL;
634
635 /* Unacked frames */
636 hdev->acl_cnt += conn->sent;
Ville Tervo6ed58ec2011-02-10 22:38:48 -0300637 } else if (conn->type == LE_LINK) {
638 if (hdev->le_pkts)
639 hdev->le_cnt += conn->sent;
640 else
641 hdev->acl_cnt += conn->sent;
Marcel Holtmann5b7f99092007-07-11 09:51:55 +0200642 } else {
643 struct hci_conn *acl = conn->link;
644 if (acl) {
645 acl->link = NULL;
646 hci_conn_put(acl);
647 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 }
649
650 tasklet_disable(&hdev->tx_task);
Marcel Holtmann7d0db0a2008-07-14 20:13:51 +0200651
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 hci_conn_hash_del(hdev, conn);
653 if (hdev->notify)
654 hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
Marcel Holtmann7d0db0a2008-07-14 20:13:51 +0200655
AnubhavGupta01d9e362011-12-17 17:14:51 +0530656 tasklet_schedule(&hdev->tx_task);
657
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 tasklet_enable(&hdev->tx_task);
Marcel Holtmann7d0db0a2008-07-14 20:13:51 +0200659
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 skb_queue_purge(&conn->data_q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661
Marcel Holtmann9eba32b2009-08-22 14:19:26 -0700662 hci_conn_put_device(conn);
Dave Young2ae9a6b2009-02-21 16:13:34 +0800663
Marcel Holtmann384943e2009-05-08 18:20:43 -0700664 hci_dev_put(hdev);
665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 return 0;
667}
668
669struct hci_chan *hci_chan_add(struct hci_dev *hdev)
670{
671 struct hci_chan *chan;
672
673 BT_DBG("%s", hdev->name);
674
675 chan = kzalloc(sizeof(struct hci_chan), GFP_ATOMIC);
676 if (!chan)
677 return NULL;
678
679 atomic_set(&chan->refcnt, 0);
680
681 hci_dev_hold(hdev);
682
683 chan->hdev = hdev;
684
685 list_add(&chan->list, &hdev->chan_list.list);
686
687 return chan;
688}
Peter Krystada8417e62012-03-21 16:58:17 -0700689EXPORT_SYMBOL(hci_chan_add);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700690
691int hci_chan_del(struct hci_chan *chan)
692{
693 BT_DBG("%s chan %p", chan->hdev->name, chan);
694
695 list_del(&chan->list);
696
697 hci_conn_put(chan->conn);
698 hci_dev_put(chan->hdev);
699
700 kfree(chan);
Tomas Targownik1be668d2011-06-30 16:30:44 -0300701
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 return 0;
703}
704
Peter Krystadd6a9ceb2011-12-01 15:44:54 -0800705int hci_chan_put(struct hci_chan *chan)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700706{
707 struct hci_cp_disconn_logical_link cp;
Mat Martineau9f8d4672011-12-14 12:10:46 -0800708 struct hci_conn *hcon;
709 u16 ll_handle;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710
711 BT_DBG("chan %p refcnt %d", chan, atomic_read(&chan->refcnt));
712 if (!atomic_dec_and_test(&chan->refcnt))
Peter Krystadd6a9ceb2011-12-01 15:44:54 -0800713 return 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700714
Mat Martineau9f8d4672011-12-14 12:10:46 -0800715 hcon = chan->conn;
716 ll_handle = chan->ll_handle;
717
718 hci_chan_del(chan);
719
720 BT_DBG("chan->conn->state %d", hcon->state);
721 if (hcon->state == BT_CONNECTED) {
722 cp.log_handle = cpu_to_le16(ll_handle);
723 hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 sizeof(cp), &cp);
Mat Martineau9f8d4672011-12-14 12:10:46 -0800725 }
Peter Krystadd6a9ceb2011-12-01 15:44:54 -0800726
727 return 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700728}
729EXPORT_SYMBOL(hci_chan_put);
730
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
732{
733 int use_src = bacmp(src, BDADDR_ANY);
734 struct hci_dev *hdev = NULL;
735 struct list_head *p;
736
737 BT_DBG("%s -> %s", batostr(src), batostr(dst));
738
739 read_lock_bh(&hci_dev_list_lock);
740
741 list_for_each(p, &hci_dev_list) {
742 struct hci_dev *d = list_entry(p, struct hci_dev, list);
743
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700744 if (d->dev_type != HCI_BREDR)
745 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746 if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
747 continue;
748
YOSHIFUJI Hideaki8e87d142007-02-09 23:24:33 +0900749 /* Simple routing:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 * No source address - find interface with bdaddr != dst
751 * Source address - find interface with bdaddr == src
752 */
753
754 if (use_src) {
755 if (!bacmp(&d->bdaddr, src)) {
756 hdev = d; break;
757 }
758 } else {
759 if (bacmp(&d->bdaddr, dst)) {
760 hdev = d; break;
761 }
762 }
763 }
764
765 if (hdev)
766 hdev = hci_dev_hold(hdev);
767
768 read_unlock_bh(&hci_dev_list_lock);
769 return hdev;
770}
771EXPORT_SYMBOL(hci_get_route);
772
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700773struct hci_dev *hci_dev_get_type(u8 amp_type)
774{
775 struct hci_dev *hdev = NULL;
776 struct hci_dev *d;
777
778 BT_DBG("amp_type %d", amp_type);
779
780 read_lock_bh(&hci_dev_list_lock);
781
782 list_for_each_entry(d, &hci_dev_list, list) {
783 if ((d->amp_type == amp_type) && test_bit(HCI_UP, &d->flags)) {
784 hdev = d;
785 break;
786 }
787 }
788
789 if (hdev)
790 hdev = hci_dev_hold(hdev);
791
792 read_unlock_bh(&hci_dev_list_lock);
793 return hdev;
794}
795EXPORT_SYMBOL(hci_dev_get_type);
796
797struct hci_dev *hci_dev_get_amp(bdaddr_t *dst)
798{
799 struct hci_dev *d;
800 struct hci_dev *hdev = NULL;
801
802 BT_DBG("%s dst %s", hdev->name, batostr(dst));
803
804 read_lock_bh(&hci_dev_list_lock);
805
806 list_for_each_entry(d, &hci_dev_list, list) {
807 struct hci_conn *conn;
808 if (d->dev_type == HCI_BREDR)
809 continue;
810 conn = hci_conn_hash_lookup_ba(d, ACL_LINK, dst);
811 if (conn) {
812 hdev = d;
813 break;
814 }
815 }
816
817 if (hdev)
818 hdev = hci_dev_hold(hdev);
819
820 read_unlock_bh(&hci_dev_list_lock);
821 return hdev;
822}
823EXPORT_SYMBOL(hci_dev_get_amp);
824
Ville Tervofcd89c02011-02-10 22:38:47 -0300825/* Create SCO, ACL or LE connection.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 * Device _must_ be locked */
Nick Pellybbcda3b2010-02-11 11:54:28 -0800827struct hci_conn *hci_connect(struct hci_dev *hdev, int type,
828 __u16 pkt_type, bdaddr_t *dst,
829 __u8 sec_level, __u8 auth_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700830{
831 struct hci_conn *acl;
Marcel Holtmann5b7f99092007-07-11 09:51:55 +0200832 struct hci_conn *sco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
834 BT_DBG("%s dst %s", hdev->name, batostr(dst));
835
Brian Gixa94b6122012-02-23 16:07:10 -0800836 if (type == LE_LINK)
837 return hci_le_connect(hdev, pkt_type, dst, sec_level,
838 auth_type, NULL);
Ville Tervofcd89c02011-02-10 22:38:47 -0300839
Andrei Emeltchenko70f230202010-12-01 16:58:25 +0200840 acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
841 if (!acl) {
Nick Pellybbcda3b2010-02-11 11:54:28 -0800842 acl = hci_conn_add(hdev, ACL_LINK, 0, dst);
Andrei Emeltchenko70f230202010-12-01 16:58:25 +0200843 if (!acl)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 return NULL;
845 }
846
847 hci_conn_hold(acl);
848
Marcel Holtmann09ab6f42008-09-09 07:19:20 +0200849 if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
Johan Hedberg765c2a92011-01-19 12:06:52 +0530850 acl->sec_level = BT_SECURITY_LOW;
851 acl->pending_sec_level = sec_level;
Marcel Holtmann09ab6f42008-09-09 07:19:20 +0200852 acl->auth_type = auth_type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853 hci_acl_connect(acl);
Marcel Holtmann09ab6f42008-09-09 07:19:20 +0200854 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
Marcel Holtmann5b7f99092007-07-11 09:51:55 +0200856 if (type == ACL_LINK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 return acl;
Marcel Holtmann5b7f99092007-07-11 09:51:55 +0200858
Srinivas Krovvidi645f4d42012-08-02 13:23:53 +0530859 /* type of connection already existing can be ESCO or SCO
860 * so check for both types before creating new */
861
Andrei Emeltchenko70f230202010-12-01 16:58:25 +0200862 sco = hci_conn_hash_lookup_ba(hdev, type, dst);
Srinivas Krovvidi645f4d42012-08-02 13:23:53 +0530863
864 if (!sco && type == ESCO_LINK) {
865 sco = hci_conn_hash_lookup_ba(hdev, SCO_LINK, dst);
866 } else if (!sco && type == SCO_LINK) {
867 /* this case can be practically not possible */
868 sco = hci_conn_hash_lookup_ba(hdev, ESCO_LINK, dst);
869 }
870
Andrei Emeltchenko70f230202010-12-01 16:58:25 +0200871 if (!sco) {
Nick Pellybbcda3b2010-02-11 11:54:28 -0800872 sco = hci_conn_add(hdev, type, pkt_type, dst);
Andrei Emeltchenko70f230202010-12-01 16:58:25 +0200873 if (!sco) {
Marcel Holtmann5b7f99092007-07-11 09:51:55 +0200874 hci_conn_put(acl);
875 return NULL;
876 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 }
Marcel Holtmann5b7f99092007-07-11 09:51:55 +0200878
879 acl->link = sco;
880 sco->link = acl;
881
882 hci_conn_hold(sco);
883
884 if (acl->state == BT_CONNECTED &&
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200885 (sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
Nick Pellyc3902162009-11-13 14:16:32 -0800886 acl->power_save = 1;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887 hci_conn_enter_active_mode(acl, 1);
Nick Pellyc3902162009-11-13 14:16:32 -0800888
Marcel Holtmanne73439d2010-07-26 10:06:00 -0400889 if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
890 /* defer SCO setup until mode change completed */
891 set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
892 return sco;
893 }
894
895 hci_sco_setup(acl, 0x00);
Marcel Holtmannb6a0dc82007-10-20 14:55:10 +0200896 }
Marcel Holtmann5b7f99092007-07-11 09:51:55 +0200897
898 return sco;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899}
900EXPORT_SYMBOL(hci_connect);
901
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700902void hci_disconnect(struct hci_conn *conn, __u8 reason)
903{
904 BT_DBG("conn %p", conn);
905
Mat Martineau3b9239a2012-02-16 11:54:30 -0800906 hci_proto_disconn_cfm(conn, reason, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907}
908EXPORT_SYMBOL(hci_disconnect);
909
910void hci_disconnect_amp(struct hci_conn *conn, __u8 reason)
911{
912 struct hci_dev *hdev = NULL;
913
914 BT_DBG("conn %p", conn);
915
916 read_lock_bh(&hci_dev_list_lock);
917
918 list_for_each_entry(hdev, &hci_dev_list, list) {
919 struct hci_conn *c;
920 if (hdev == conn->hdev)
921 continue;
922 if (hdev->amp_type == HCI_BREDR)
923 continue;
924 c = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &conn->dst);
925 if (c)
926 hci_disconnect(c, reason);
927 }
928
929 read_unlock_bh(&hci_dev_list_lock);
930}
931
Marcel Holtmanne7c29cb2008-09-09 07:19:20 +0200932/* Check link security requirement */
933int hci_conn_check_link_mode(struct hci_conn *conn)
934{
935 BT_DBG("conn %p", conn);
936
937 if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 &&
938 !(conn->link_mode & HCI_LM_ENCRYPT))
939 return 0;
940
941 return 1;
942}
943EXPORT_SYMBOL(hci_conn_check_link_mode);
944
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945/* Authenticate remote device */
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100946static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
948 BT_DBG("conn %p", conn);
949
Johan Hedberg765c2a92011-01-19 12:06:52 +0530950 if (conn->pending_sec_level > sec_level)
951 sec_level = conn->pending_sec_level;
952
Marcel Holtmann96a31832009-02-12 16:23:03 +0100953 if (sec_level > conn->sec_level)
Johan Hedberg765c2a92011-01-19 12:06:52 +0530954 conn->pending_sec_level = sec_level;
Marcel Holtmann96a31832009-02-12 16:23:03 +0100955 else if (conn->link_mode & HCI_LM_AUTH)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 return 1;
957
Johan Hedberg65cf6862011-01-19 12:06:49 +0530958 /* Make sure we preserve an existing MITM requirement*/
959 auth_type |= (conn->auth_type & 0x01);
Marcel Holtmann96a31832009-02-12 16:23:03 +0100960 conn->auth_type = auth_type;
Brian Gixa68668b2011-08-11 15:49:36 -0700961 conn->auth_initiator = 1;
Marcel Holtmann96a31832009-02-12 16:23:03 +0100962
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
964 struct hci_cp_auth_requested cp;
Peter Hurleya5e5b082012-01-13 15:11:30 +0100965
966 /* encrypt must be pending if auth is also pending */
967 set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend);
968
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -0700969 cp.handle = cpu_to_le16(conn->handle);
Marcel Holtmann40be4922008-07-14 20:13:50 +0200970 hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
971 sizeof(cp), &cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 }
Marcel Holtmann8c1b2352009-01-15 21:58:04 +0100973
Linus Torvalds1da177e2005-04-16 15:20:36 -0700974 return 0;
975}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976
Marcel Holtmann8c1b2352009-01-15 21:58:04 +0100977/* Enable security */
Marcel Holtmann0684e5f2009-02-09 02:48:38 +0100978int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700979{
Brian Gixa68668b2011-08-11 15:49:36 -0700980 BT_DBG("conn %p %d %d", conn, sec_level, auth_type);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981
Marcel Holtmann8c1b2352009-01-15 21:58:04 +0100982 if (sec_level == BT_SECURITY_SDP)
983 return 1;
984
Marcel Holtmann3fdca1e2009-04-28 09:04:55 -0700985 if (sec_level == BT_SECURITY_LOW &&
986 (!conn->ssp_mode || !conn->hdev->ssp_mode))
987 return 1;
Marcel Holtmann8c1b2352009-01-15 21:58:04 +0100988
Brian Gix2e2f50d2011-09-13 12:36:04 -0700989 if (conn->type == LE_LINK) {
990 if (conn->pending_sec_level > sec_level)
991 sec_level = conn->pending_sec_level;
Waldemar Rymarkiewicz13d39312011-04-28 12:07:55 +0200992
Brian Gix2e2f50d2011-09-13 12:36:04 -0700993 if (sec_level > conn->sec_level)
994 conn->pending_sec_level = sec_level;
995 hci_proto_connect_cfm(conn, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 return 0;
Brian Gix2e2f50d2011-09-13 12:36:04 -0700997 } else if (conn->link_mode & HCI_LM_ENCRYPT) {
998 return hci_conn_auth(conn, sec_level, auth_type);
Ilia Kolomisnkyedc44dd2011-06-15 06:52:26 +0300999 } else if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
Brian Gix2e2f50d2011-09-13 12:36:04 -07001000 return 0;
1001 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001002
1003 if (hci_conn_auth(conn, sec_level, auth_type)) {
1004 struct hci_cp_set_conn_encrypt cp;
Prabhakaran Mcafface82012-04-10 11:38:35 +05301005 if (timer_pending(&conn->encrypt_pause_timer)) {
1006 BT_INFO("encrypt_pause_timer is pending");
1007 return 0;
1008 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 cp.handle = cpu_to_le16(conn->handle);
1010 cp.encrypt = 1;
1011 hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
1012 sizeof(cp), &cp);
1013 }
1014
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 return 0;
1016}
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01001017EXPORT_SYMBOL(hci_conn_security);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001018
1019/* Change link key */
1020int hci_conn_change_link_key(struct hci_conn *conn)
1021{
1022 BT_DBG("conn %p", conn);
1023
1024 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
1025 struct hci_cp_change_conn_link_key cp;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001026 cp.handle = cpu_to_le16(conn->handle);
Marcel Holtmann40be4922008-07-14 20:13:50 +02001027 hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
1028 sizeof(cp), &cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 }
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01001030
Linus Torvalds1da177e2005-04-16 15:20:36 -07001031 return 0;
1032}
1033EXPORT_SYMBOL(hci_conn_change_link_key);
1034
1035/* Switch role */
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01001036int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037{
1038 BT_DBG("conn %p", conn);
1039
1040 if (!role && conn->link_mode & HCI_LM_MASTER)
1041 return 1;
1042
1043 if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) {
1044 struct hci_cp_switch_role cp;
1045 bacpy(&cp.bdaddr, &conn->dst);
1046 cp.role = role;
Marcel Holtmanna9de9242007-10-20 13:33:56 +02001047 hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001048 }
Marcel Holtmann8c1b2352009-01-15 21:58:04 +01001049
Linus Torvalds1da177e2005-04-16 15:20:36 -07001050 return 0;
1051}
1052EXPORT_SYMBOL(hci_conn_switch_role);
1053
Marcel Holtmann04837f62006-07-03 10:02:33 +02001054/* Enter active mode */
Jaikumar Ganesh514abe62011-05-23 18:06:04 -07001055void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)
Marcel Holtmann04837f62006-07-03 10:02:33 +02001056{
1057 struct hci_dev *hdev = conn->hdev;
1058
1059 BT_DBG("conn %p mode %d", conn, conn->mode);
1060
1061 if (test_bit(HCI_RAW, &hdev->flags))
1062 return;
1063
Sunny Kapdi39eaba32012-07-22 21:29:38 -07001064 if (conn->type == LE_LINK)
1065 return;
1066
Jaikumar Ganesh514abe62011-05-23 18:06:04 -07001067 if (conn->mode != HCI_CM_SNIFF)
1068 goto timer;
1069
1070 if (!conn->power_save && !force_active)
Marcel Holtmann04837f62006-07-03 10:02:33 +02001071 goto timer;
1072
1073 if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
1074 struct hci_cp_exit_sniff_mode cp;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001075 cp.handle = cpu_to_le16(conn->handle);
Marcel Holtmanna9de9242007-10-20 13:33:56 +02001076 hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
Marcel Holtmann04837f62006-07-03 10:02:33 +02001077 }
1078
1079timer:
Rahul Kashyapb44f9e22012-05-03 16:45:17 +05301080 if (hdev->idle_timeout > 0) {
Srinivas Krovvidi6aadc412012-09-03 18:47:50 +05301081 spin_lock_bh(&conn->lock);
1082 if (conn->conn_valid) {
1083 mod_timer(&conn->idle_timer,
1084 jiffies + msecs_to_jiffies(hdev->idle_timeout));
1085 wake_lock(&conn->idle_lock);
1086 }
1087 spin_unlock_bh(&conn->lock);
Rahul Kashyapb44f9e22012-05-03 16:45:17 +05301088 }
Marcel Holtmann04837f62006-07-03 10:02:33 +02001089}
1090
Archana Ramachandran26a752b2011-12-20 11:27:40 -08001091static inline void hci_conn_stop_rssi_timer(struct hci_conn *conn)
1092{
1093 BT_DBG("conn %p", conn);
1094 cancel_delayed_work(&conn->rssi_update_work);
1095}
1096
1097static inline void hci_conn_start_rssi_timer(struct hci_conn *conn,
1098 u16 interval)
1099{
1100 struct hci_dev *hdev = conn->hdev;
1101 BT_DBG("conn %p, pending %d", conn,
1102 delayed_work_pending(&conn->rssi_update_work));
1103 if (!delayed_work_pending(&conn->rssi_update_work)) {
1104 queue_delayed_work(hdev->workqueue, &conn->rssi_update_work,
1105 msecs_to_jiffies(interval));
1106 }
1107}
1108
1109void hci_conn_set_rssi_reporter(struct hci_conn *conn,
1110 s8 rssi_threshold, u16 interval, u8 updateOnThreshExceed)
1111{
1112 if (conn) {
1113 conn->rssi_threshold = rssi_threshold;
1114 conn->rssi_update_interval = interval;
1115 conn->rssi_update_thresh_exceed = updateOnThreshExceed;
1116 hci_conn_start_rssi_timer(conn, interval);
1117 }
1118}
1119
1120void hci_conn_unset_rssi_reporter(struct hci_conn *conn)
1121{
1122 if (conn) {
1123 BT_DBG("Deleting the rssi_update_timer");
1124 hci_conn_stop_rssi_timer(conn);
1125 }
1126}
1127
Marcel Holtmann04837f62006-07-03 10:02:33 +02001128/* Enter sniff mode */
1129void hci_conn_enter_sniff_mode(struct hci_conn *conn)
1130{
1131 struct hci_dev *hdev = conn->hdev;
1132
1133 BT_DBG("conn %p mode %d", conn, conn->mode);
1134
1135 if (test_bit(HCI_RAW, &hdev->flags))
1136 return;
1137
Sunny Kapdi39eaba32012-07-22 21:29:38 -07001138 if (conn->type == LE_LINK)
1139 return;
1140
Marcel Holtmann04837f62006-07-03 10:02:33 +02001141 if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
1142 return;
1143
Srinivas Krovvidi32ba9352012-01-26 10:48:08 +05301144 if (conn->mode != HCI_CM_ACTIVE ||
1145 !(conn->link_policy & HCI_LP_SNIFF) ||
1146 (hci_find_link_key(hdev, &conn->dst) == NULL))
Marcel Holtmann04837f62006-07-03 10:02:33 +02001147 return;
1148
1149 if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
1150 struct hci_cp_sniff_subrate cp;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001151 cp.handle = cpu_to_le16(conn->handle);
1152 cp.max_latency = cpu_to_le16(0);
1153 cp.min_remote_timeout = cpu_to_le16(0);
1154 cp.min_local_timeout = cpu_to_le16(0);
Marcel Holtmanna9de9242007-10-20 13:33:56 +02001155 hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
Marcel Holtmann04837f62006-07-03 10:02:33 +02001156 }
1157
1158 if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
1159 struct hci_cp_sniff_mode cp;
YOSHIFUJI Hideakiaca31922007-03-25 20:12:50 -07001160 cp.handle = cpu_to_le16(conn->handle);
1161 cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
1162 cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
1163 cp.attempt = cpu_to_le16(4);
1164 cp.timeout = cpu_to_le16(1);
Marcel Holtmanna9de9242007-10-20 13:33:56 +02001165 hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
Marcel Holtmann04837f62006-07-03 10:02:33 +02001166 }
1167}
1168
Peter Krystada8417e62012-03-21 16:58:17 -07001169struct hci_chan *hci_chan_create(struct hci_chan *chan,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs)
1171{
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 struct hci_cp_create_logical_link cp;
1173
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174 chan->state = BT_CONNECT;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 chan->tx_fs = *tx_fs;
1176 chan->rx_fs = *rx_fs;
1177 cp.phy_handle = chan->conn->handle;
1178 cp.tx_fs.id = chan->tx_fs.id;
1179 cp.tx_fs.type = chan->tx_fs.type;
1180 cp.tx_fs.max_sdu = cpu_to_le16(chan->tx_fs.max_sdu);
1181 cp.tx_fs.sdu_arr_time = cpu_to_le32(chan->tx_fs.sdu_arr_time);
1182 cp.tx_fs.acc_latency = cpu_to_le32(chan->tx_fs.acc_latency);
1183 cp.tx_fs.flush_to = cpu_to_le32(chan->tx_fs.flush_to);
1184 cp.rx_fs.id = chan->rx_fs.id;
1185 cp.rx_fs.type = chan->rx_fs.type;
1186 cp.rx_fs.max_sdu = cpu_to_le16(chan->rx_fs.max_sdu);
1187 cp.rx_fs.sdu_arr_time = cpu_to_le32(chan->rx_fs.sdu_arr_time);
1188 cp.rx_fs.acc_latency = cpu_to_le32(chan->rx_fs.acc_latency);
1189 cp.rx_fs.flush_to = cpu_to_le32(chan->rx_fs.flush_to);
1190 hci_conn_hold(chan->conn);
Peter Krystada8417e62012-03-21 16:58:17 -07001191 if (chan->conn->out)
1192 hci_send_cmd(chan->conn->hdev, HCI_OP_CREATE_LOGICAL_LINK,
1193 sizeof(cp), &cp);
1194 else
1195 hci_send_cmd(chan->conn->hdev, HCI_OP_ACCEPT_LOGICAL_LINK,
1196 sizeof(cp), &cp);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001197 return chan;
1198}
1199EXPORT_SYMBOL(hci_chan_create);
1200
1201void hci_chan_modify(struct hci_chan *chan,
1202 struct hci_ext_fs *tx_fs, struct hci_ext_fs *rx_fs)
1203{
1204 struct hci_cp_flow_spec_modify cp;
1205
1206 chan->tx_fs = *tx_fs;
1207 chan->rx_fs = *rx_fs;
1208 cp.log_handle = cpu_to_le16(chan->ll_handle);
1209 cp.tx_fs.id = tx_fs->id;
1210 cp.tx_fs.type = tx_fs->type;
1211 cp.tx_fs.max_sdu = cpu_to_le16(tx_fs->max_sdu);
1212 cp.tx_fs.sdu_arr_time = cpu_to_le32(tx_fs->sdu_arr_time);
1213 cp.tx_fs.acc_latency = cpu_to_le32(tx_fs->acc_latency);
1214 cp.tx_fs.flush_to = cpu_to_le32(tx_fs->flush_to);
1215 cp.rx_fs.id = rx_fs->id;
1216 cp.rx_fs.type = rx_fs->type;
1217 cp.rx_fs.max_sdu = cpu_to_le16(rx_fs->max_sdu);
1218 cp.rx_fs.sdu_arr_time = cpu_to_le32(rx_fs->sdu_arr_time);
1219 cp.rx_fs.acc_latency = cpu_to_le32(rx_fs->acc_latency);
1220 cp.rx_fs.flush_to = cpu_to_le32(rx_fs->flush_to);
1221 hci_conn_hold(chan->conn);
1222 hci_send_cmd(chan->conn->hdev, HCI_OP_FLOW_SPEC_MODIFY, sizeof(cp),
1223 &cp);
1224}
1225EXPORT_SYMBOL(hci_chan_modify);
1226
Linus Torvalds1da177e2005-04-16 15:20:36 -07001227/* Drop all connection on the device */
Mat Martineau3b9239a2012-02-16 11:54:30 -08001228void hci_conn_hash_flush(struct hci_dev *hdev, u8 is_process)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001229{
1230 struct hci_conn_hash *h = &hdev->conn_hash;
1231 struct list_head *p;
1232
1233 BT_DBG("hdev %s", hdev->name);
1234
1235 p = h->list.next;
1236 while (p != &h->list) {
1237 struct hci_conn *c;
1238
1239 c = list_entry(p, struct hci_conn, list);
1240 p = p->next;
1241
1242 c->state = BT_CLOSED;
1243
Mat Martineau3b9239a2012-02-16 11:54:30 -08001244 hci_proto_disconn_cfm(c, 0x16, is_process);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 hci_conn_del(c);
1246 }
1247}
1248
Marcel Holtmanna9de9242007-10-20 13:33:56 +02001249/* Check pending connect attempts */
1250void hci_conn_check_pending(struct hci_dev *hdev)
1251{
1252 struct hci_conn *conn;
1253
1254 BT_DBG("hdev %s", hdev->name);
1255
1256 hci_dev_lock(hdev);
1257
1258 conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
1259 if (conn)
1260 hci_acl_connect(conn);
1261
1262 hci_dev_unlock(hdev);
1263}
1264
Marcel Holtmann9eba32b2009-08-22 14:19:26 -07001265void hci_conn_hold_device(struct hci_conn *conn)
1266{
1267 atomic_inc(&conn->devref);
1268}
1269EXPORT_SYMBOL(hci_conn_hold_device);
1270
1271void hci_conn_put_device(struct hci_conn *conn)
1272{
1273 if (atomic_dec_and_test(&conn->devref))
1274 hci_conn_del_sysfs(conn);
1275}
1276EXPORT_SYMBOL(hci_conn_put_device);
1277
Linus Torvalds1da177e2005-04-16 15:20:36 -07001278int hci_get_conn_list(void __user *arg)
1279{
1280 struct hci_conn_list_req req, *cl;
1281 struct hci_conn_info *ci;
1282 struct hci_dev *hdev;
1283 struct list_head *p;
1284 int n = 0, size, err;
1285
1286 if (copy_from_user(&req, arg, sizeof(req)))
1287 return -EFAULT;
1288
1289 if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
1290 return -EINVAL;
1291
1292 size = sizeof(req) + req.conn_num * sizeof(*ci);
1293
Andrei Emeltchenko70f230202010-12-01 16:58:25 +02001294 cl = kmalloc(size, GFP_KERNEL);
1295 if (!cl)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 return -ENOMEM;
1297
Andrei Emeltchenko70f230202010-12-01 16:58:25 +02001298 hdev = hci_dev_get(req.dev_id);
1299 if (!hdev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001300 kfree(cl);
1301 return -ENODEV;
1302 }
1303
1304 ci = cl->conn_info;
1305
1306 hci_dev_lock_bh(hdev);
1307 list_for_each(p, &hdev->conn_hash.list) {
1308 register struct hci_conn *c;
1309 c = list_entry(p, struct hci_conn, list);
1310
1311 bacpy(&(ci + n)->bdaddr, &c->dst);
1312 (ci + n)->handle = c->handle;
1313 (ci + n)->type = c->type;
1314 (ci + n)->out = c->out;
1315 (ci + n)->state = c->state;
1316 (ci + n)->link_mode = c->link_mode;
Nick Pellyc1728492009-12-09 00:15:41 -08001317 if (c->type == SCO_LINK) {
1318 (ci + n)->mtu = hdev->sco_mtu;
1319 (ci + n)->cnt = hdev->sco_cnt;
1320 (ci + n)->pkts = hdev->sco_pkts;
1321 } else {
1322 (ci + n)->mtu = hdev->acl_mtu;
1323 (ci + n)->cnt = hdev->acl_cnt;
1324 (ci + n)->pkts = hdev->acl_pkts;
1325 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326 if (++n >= req.conn_num)
1327 break;
1328 }
1329 hci_dev_unlock_bh(hdev);
1330
1331 cl->dev_id = hdev->id;
1332 cl->conn_num = n;
1333 size = sizeof(req) + n * sizeof(*ci);
1334
1335 hci_dev_put(hdev);
1336
1337 err = copy_to_user(arg, cl, size);
1338 kfree(cl);
1339
1340 return err ? -EFAULT : 0;
1341}
1342
1343int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
1344{
1345 struct hci_conn_info_req req;
1346 struct hci_conn_info ci;
1347 struct hci_conn *conn;
1348 char __user *ptr = arg + sizeof(req);
1349
1350 if (copy_from_user(&req, arg, sizeof(req)))
1351 return -EFAULT;
1352
1353 hci_dev_lock_bh(hdev);
1354 conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
1355 if (conn) {
1356 bacpy(&ci.bdaddr, &conn->dst);
1357 ci.handle = conn->handle;
1358 ci.type = conn->type;
1359 ci.out = conn->out;
1360 ci.state = conn->state;
1361 ci.link_mode = conn->link_mode;
Nick Pellyc1728492009-12-09 00:15:41 -08001362 if (req.type == SCO_LINK) {
1363 ci.mtu = hdev->sco_mtu;
1364 ci.cnt = hdev->sco_cnt;
1365 ci.pkts = hdev->sco_pkts;
1366 } else {
1367 ci.mtu = hdev->acl_mtu;
1368 ci.cnt = hdev->acl_cnt;
1369 ci.pkts = hdev->acl_pkts;
1370 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001371 ci.pending_sec_level = conn->pending_sec_level;
1372 ci.ssp_mode = conn->ssp_mode;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 }
1374 hci_dev_unlock_bh(hdev);
1375
1376 if (!conn)
1377 return -ENOENT;
1378
1379 return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
1380}
Marcel Holtmann40be4922008-07-14 20:13:50 +02001381
1382int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
1383{
1384 struct hci_auth_info_req req;
1385 struct hci_conn *conn;
1386
1387 if (copy_from_user(&req, arg, sizeof(req)))
1388 return -EFAULT;
1389
1390 hci_dev_lock_bh(hdev);
1391 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
1392 if (conn)
1393 req.type = conn->auth_type;
1394 hci_dev_unlock_bh(hdev);
1395
1396 if (!conn)
1397 return -ENOENT;
1398
1399 return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
1400}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401
1402int hci_set_auth_info(struct hci_dev *hdev, void __user *arg)
1403{
1404 struct hci_auth_info_req req;
1405 struct hci_conn *conn;
1406
1407 if (copy_from_user(&req, arg, sizeof(req)))
1408 return -EFAULT;
1409
1410 hci_dev_lock_bh(hdev);
1411 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
Srinivas Krovvidi52b05ba2012-08-27 18:32:45 +05301412 if (conn) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 conn->auth_type = req.type;
Srinivas Krovvidi52b05ba2012-08-27 18:32:45 +05301414 switch (conn->auth_type) {
1415 case HCI_AT_NO_BONDING:
1416 conn->pending_sec_level = BT_SECURITY_LOW;
1417 break;
1418 case HCI_AT_DEDICATED_BONDING:
1419 case HCI_AT_GENERAL_BONDING:
1420 conn->pending_sec_level = BT_SECURITY_MEDIUM;
1421 break;
1422 case HCI_AT_DEDICATED_BONDING_MITM:
1423 case HCI_AT_GENERAL_BONDING_MITM:
1424 conn->pending_sec_level = BT_SECURITY_HIGH;
1425 break;
1426 default:
1427 break;
1428 }
1429 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 hci_dev_unlock_bh(hdev);
1431
1432 if (!conn)
1433 return -ENOENT;
1434
1435 return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
1436}