hci_conn.c 16.5 KB
Newer Older
1
/*
L
Linus Torvalds 已提交
2
   BlueZ - Bluetooth protocol stack for Linux
3
   Copyright (c) 2000-2001, 2010, Code Aurora Forum. All rights reserved.
L
Linus Torvalds 已提交
4 5 6 7 8 9 10 11 12 13 14

   Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 2 as
   published by the Free Software Foundation;

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 16 17
   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
L
Linus Torvalds 已提交
18 19
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

20 21
   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
L
Linus Torvalds 已提交
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
   SOFTWARE IS DISCLAIMED.
*/

/* Bluetooth HCI connection handling. */

#include <linux/module.h>

#include <linux/types.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/fcntl.h>
#include <linux/init.h>
#include <linux/skbuff.h>
#include <linux/interrupt.h>
#include <linux/notifier.h>
#include <net/sock.h>

#include <asm/system.h>
A
Andrei Emeltchenko 已提交
42
#include <linux/uaccess.h>
L
Linus Torvalds 已提交
43 44 45 46 47
#include <asm/unaligned.h>

#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>

48
void hci_acl_connect(struct hci_conn *conn)
L
Linus Torvalds 已提交
49 50 51 52 53 54 55 56
{
	struct hci_dev *hdev = conn->hdev;
	struct inquiry_entry *ie;
	struct hci_cp_create_conn cp;

	BT_DBG("%p", conn);

	conn->state = BT_CONNECT;
57 58
	conn->out = 1;

L
Linus Torvalds 已提交
59 60
	conn->link_mode = HCI_LM_MASTER;

61 62
	conn->attempt++;

63 64
	conn->link_policy = hdev->link_policy;

L
Linus Torvalds 已提交
65 66 67 68
	memset(&cp, 0, sizeof(cp));
	bacpy(&cp.bdaddr, &conn->dst);
	cp.pscan_rep_mode = 0x02;

A
Andrei Emeltchenko 已提交
69 70
	ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
	if (ie) {
71 72 73 74 75 76 77
		if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
			cp.pscan_rep_mode = ie->data.pscan_rep_mode;
			cp.pscan_mode     = ie->data.pscan_mode;
			cp.clock_offset   = ie->data.clock_offset |
							cpu_to_le16(0x8000);
		}

L
Linus Torvalds 已提交
78
		memcpy(conn->dev_class, ie->data.dev_class, 3);
79
		conn->ssp_mode = ie->data.ssp_mode;
L
Linus Torvalds 已提交
80 81
	}

82
	cp.pkt_type = cpu_to_le16(conn->pkt_type);
L
Linus Torvalds 已提交
83
	if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
84
		cp.role_switch = 0x01;
L
Linus Torvalds 已提交
85
	else
86
		cp.role_switch = 0x00;
87

88
	hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);
L
Linus Torvalds 已提交
89 90
}

91 92 93 94 95 96 97 98 99 100
static void hci_acl_connect_cancel(struct hci_conn *conn)
{
	struct hci_cp_create_conn_cancel cp;

	BT_DBG("%p", conn);

	if (conn->hdev->hci_ver < 2)
		return;

	bacpy(&cp.bdaddr, &conn->dst);
101
	hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);
102 103
}

L
Linus Torvalds 已提交
104 105 106 107 108 109 110 111
void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
{
	struct hci_cp_disconnect cp;

	BT_DBG("%p", conn);

	conn->state = BT_DISCONN;

112
	cp.handle = cpu_to_le16(conn->handle);
L
Linus Torvalds 已提交
113
	cp.reason = reason;
114
	hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);
L
Linus Torvalds 已提交
115 116 117 118 119 120 121 122 123 124 125 126
}

void hci_add_sco(struct hci_conn *conn, __u16 handle)
{
	struct hci_dev *hdev = conn->hdev;
	struct hci_cp_add_sco cp;

	BT_DBG("%p", conn);

	conn->state = BT_CONNECT;
	conn->out = 1;

127 128
	conn->attempt++;

129
	cp.handle   = cpu_to_le16(handle);
130
	cp.pkt_type = cpu_to_le16(conn->pkt_type);
L
Linus Torvalds 已提交
131

132
	hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);
L
Linus Torvalds 已提交
133 134
}

135 136 137 138 139 140 141 142 143 144
void hci_setup_sync(struct hci_conn *conn, __u16 handle)
{
	struct hci_dev *hdev = conn->hdev;
	struct hci_cp_setup_sync_conn cp;

	BT_DBG("%p", conn);

	conn->state = BT_CONNECT;
	conn->out = 1;

145 146
	conn->attempt++;

147
	cp.handle   = cpu_to_le16(handle);
148
	cp.pkt_type = cpu_to_le16(conn->pkt_type);
149 150 151 152 153 154 155 156 157 158

	cp.tx_bandwidth   = cpu_to_le32(0x00001f40);
	cp.rx_bandwidth   = cpu_to_le32(0x00001f40);
	cp.max_latency    = cpu_to_le16(0xffff);
	cp.voice_setting  = cpu_to_le16(hdev->voice_setting);
	cp.retrans_effort = 0xff;

	hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp);
}

159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
/* Device _must_ be locked */
void hci_sco_setup(struct hci_conn *conn, __u8 status)
{
	struct hci_conn *sco = conn->link;

	BT_DBG("%p", conn);

	if (!sco)
		return;

	if (!status) {
		if (lmp_esco_capable(conn->hdev))
			hci_setup_sync(sco, conn->handle);
		else
			hci_add_sco(sco, conn->handle);
	} else {
		hci_proto_connect_cfm(sco, status);
		hci_conn_del(sco);
	}
}

L
Linus Torvalds 已提交
180 181
static void hci_conn_timeout(unsigned long arg)
{
182 183
	struct hci_conn *conn = (void *) arg;
	struct hci_dev *hdev = conn->hdev;
184
	__u8 reason;
L
Linus Torvalds 已提交
185 186 187 188 189 190 191

	BT_DBG("conn %p state %d", conn, conn->state);

	if (atomic_read(&conn->refcnt))
		return;

	hci_dev_lock(hdev);
192 193 194

	switch (conn->state) {
	case BT_CONNECT:
195
	case BT_CONNECT2:
196
		if (conn->type == ACL_LINK && conn->out)
197
			hci_acl_connect_cancel(conn);
198
		break;
199
	case BT_CONFIG:
200
	case BT_CONNECTED:
201 202
		reason = hci_proto_disconn_ind(conn);
		hci_acl_disconn(conn, reason);
203 204
		break;
	default:
L
Linus Torvalds 已提交
205
		conn->state = BT_CLOSED;
206 207 208
		break;
	}

L
Linus Torvalds 已提交
209 210 211
	hci_dev_unlock(hdev);
}

212
static void hci_conn_idle(unsigned long arg)
L
Linus Torvalds 已提交
213
{
214 215 216 217 218
	struct hci_conn *conn = (void *) arg;

	BT_DBG("conn %p mode %d", conn, conn->mode);

	hci_conn_enter_sniff_mode(conn);
L
Linus Torvalds 已提交
219 220 221 222 223 224 225 226
}

struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
{
	struct hci_conn *conn;

	BT_DBG("%s dst %s", hdev->name, batostr(dst));

227 228
	conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC);
	if (!conn)
L
Linus Torvalds 已提交
229 230 231
		return NULL;

	bacpy(&conn->dst, dst);
232 233 234 235
	conn->hdev  = hdev;
	conn->type  = type;
	conn->mode  = HCI_CM_ACTIVE;
	conn->state = BT_OPEN;
236
	conn->auth_type = HCI_AT_GENERAL_BONDING;
L
Linus Torvalds 已提交
237

238
	conn->power_save = 1;
239
	conn->disc_timeout = HCI_DISCONN_TIMEOUT;
240

241 242 243 244 245 246
	switch (type) {
	case ACL_LINK:
		conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;
		break;
	case SCO_LINK:
		if (lmp_esco_capable(hdev))
247 248
			conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
					(hdev->esco_type & EDR_ESCO_MASK);
249 250 251 252
		else
			conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
		break;
	case ESCO_LINK:
253
		conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
254 255 256
		break;
	}

L
Linus Torvalds 已提交
257
	skb_queue_head_init(&conn->data_q);
258

259 260
	setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);
	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn);
L
Linus Torvalds 已提交
261 262 263 264 265 266 267 268 269 270 271

	atomic_set(&conn->refcnt, 0);

	hci_dev_hold(hdev);

	tasklet_disable(&hdev->tx_task);

	hci_conn_hash_add(hdev, conn);
	if (hdev->notify)
		hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);

272 273
	atomic_set(&conn->devref, 0);

274 275
	hci_conn_init_sysfs(conn);

L
Linus Torvalds 已提交
276 277 278 279 280 281 282 283 284 285 286
	tasklet_enable(&hdev->tx_task);

	return conn;
}

int hci_conn_del(struct hci_conn *conn)
{
	struct hci_dev *hdev = conn->hdev;

	BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);

287 288 289
	del_timer(&conn->idle_timer);

	del_timer(&conn->disc_timer);
L
Linus Torvalds 已提交
290

291
	if (conn->type == ACL_LINK) {
L
Linus Torvalds 已提交
292 293 294 295 296 297
		struct hci_conn *sco = conn->link;
		if (sco)
			sco->link = NULL;

		/* Unacked frames */
		hdev->acl_cnt += conn->sent;
298 299 300 301 302 303
	} else {
		struct hci_conn *acl = conn->link;
		if (acl) {
			acl->link = NULL;
			hci_conn_put(acl);
		}
L
Linus Torvalds 已提交
304 305 306
	}

	tasklet_disable(&hdev->tx_task);
307

L
Linus Torvalds 已提交
308 309 310
	hci_conn_hash_del(hdev, conn);
	if (hdev->notify)
		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
311

L
Linus Torvalds 已提交
312
	tasklet_enable(&hdev->tx_task);
313

L
Linus Torvalds 已提交
314 315
	skb_queue_purge(&conn->data_q);

316
	hci_conn_put_device(conn);
317

318 319
	hci_dev_put(hdev);

L
Linus Torvalds 已提交
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338
	return 0;
}

struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
{
	int use_src = bacmp(src, BDADDR_ANY);
	struct hci_dev *hdev = NULL;
	struct list_head *p;

	BT_DBG("%s -> %s", batostr(src), batostr(dst));

	read_lock_bh(&hci_dev_list_lock);

	list_for_each(p, &hci_dev_list) {
		struct hci_dev *d = list_entry(p, struct hci_dev, list);

		if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
			continue;

339
		/* Simple routing:
L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364
		 *   No source address - find interface with bdaddr != dst
		 *   Source address    - find interface with bdaddr == src
		 */

		if (use_src) {
			if (!bacmp(&d->bdaddr, src)) {
				hdev = d; break;
			}
		} else {
			if (bacmp(&d->bdaddr, dst)) {
				hdev = d; break;
			}
		}
	}

	if (hdev)
		hdev = hci_dev_hold(hdev);

	read_unlock_bh(&hci_dev_list_lock);
	return hdev;
}
EXPORT_SYMBOL(hci_get_route);

/* Create SCO or ACL connection.
 * Device _must_ be locked */
365
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
L
Linus Torvalds 已提交
366 367
{
	struct hci_conn *acl;
368
	struct hci_conn *sco;
L
Linus Torvalds 已提交
369 370 371

	BT_DBG("%s dst %s", hdev->name, batostr(dst));

A
Andrei Emeltchenko 已提交
372 373 374 375
	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
	if (!acl) {
		acl = hci_conn_add(hdev, ACL_LINK, dst);
		if (!acl)
L
Linus Torvalds 已提交
376 377 378 379 380
			return NULL;
	}

	hci_conn_hold(acl);

381
	if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
382 383
		acl->sec_level = BT_SECURITY_LOW;
		acl->pending_sec_level = sec_level;
384
		acl->auth_type = auth_type;
L
Linus Torvalds 已提交
385
		hci_acl_connect(acl);
386
	}
L
Linus Torvalds 已提交
387

388 389
	if (type == ACL_LINK)
		return acl;
L
Linus Torvalds 已提交
390

A
Andrei Emeltchenko 已提交
391 392 393 394
	sco = hci_conn_hash_lookup_ba(hdev, type, dst);
	if (!sco) {
		sco = hci_conn_add(hdev, type, dst);
		if (!sco) {
395 396
			hci_conn_put(acl);
			return NULL;
L
Linus Torvalds 已提交
397
		}
398
	}
L
Linus Torvalds 已提交
399

400 401
	acl->link = sco;
	sco->link = acl;
L
Linus Torvalds 已提交
402

403
	hci_conn_hold(sco);
L
Linus Torvalds 已提交
404

405
	if (acl->state == BT_CONNECTED &&
406
			(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
407 408 409
		acl->power_save = 1;
		hci_conn_enter_active_mode(acl);

410 411 412 413 414 415 416
		if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) {
			/* defer SCO setup until mode change completed */
			set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend);
			return sco;
		}

		hci_sco_setup(acl, 0x00);
417
	}
418 419

	return sco;
L
Linus Torvalds 已提交
420 421 422
}
EXPORT_SYMBOL(hci_connect);

423 424 425 426 427 428 429 430 431 432 433 434 435
/* Check link security requirement */
int hci_conn_check_link_mode(struct hci_conn *conn)
{
	BT_DBG("conn %p", conn);

	if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 &&
					!(conn->link_mode & HCI_LM_ENCRYPT))
		return 0;

	return 1;
}
EXPORT_SYMBOL(hci_conn_check_link_mode);

L
Linus Torvalds 已提交
436
/* Authenticate remote device */
437
static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
L
Linus Torvalds 已提交
438 439 440
{
	BT_DBG("conn %p", conn);

441 442 443
	if (conn->pending_sec_level > sec_level)
		sec_level = conn->pending_sec_level;

444
	if (sec_level > conn->sec_level)
445
		conn->pending_sec_level = sec_level;
446
	else if (conn->link_mode & HCI_LM_AUTH)
L
Linus Torvalds 已提交
447 448
		return 1;

449 450 451
	/* Make sure we preserve an existing MITM requirement*/
	auth_type |= (conn->auth_type & 0x01);

452 453
	conn->auth_type = auth_type;

L
Linus Torvalds 已提交
454 455
	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
		struct hci_cp_auth_requested cp;
456
		cp.handle = cpu_to_le16(conn->handle);
457 458
		hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
							sizeof(cp), &cp);
L
Linus Torvalds 已提交
459
	}
460

L
Linus Torvalds 已提交
461 462 463
	return 0;
}

464
/* Enable security */
465
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
L
Linus Torvalds 已提交
466 467 468
{
	BT_DBG("conn %p", conn);

469 470 471
	if (sec_level == BT_SECURITY_SDP)
		return 1;

472 473 474
	if (sec_level == BT_SECURITY_LOW &&
				(!conn->ssp_mode || !conn->hdev->ssp_mode))
		return 1;
475

L
Linus Torvalds 已提交
476
	if (conn->link_mode & HCI_LM_ENCRYPT)
477
		return hci_conn_auth(conn, sec_level, auth_type);
L
Linus Torvalds 已提交
478 479 480 481

	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
		return 0;

482
	if (hci_conn_auth(conn, sec_level, auth_type)) {
L
Linus Torvalds 已提交
483
		struct hci_cp_set_conn_encrypt cp;
484
		cp.handle  = cpu_to_le16(conn->handle);
485
		cp.encrypt = 1;
486 487
		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
							sizeof(cp), &cp);
L
Linus Torvalds 已提交
488
	}
489

L
Linus Torvalds 已提交
490 491
	return 0;
}
492
EXPORT_SYMBOL(hci_conn_security);
L
Linus Torvalds 已提交
493 494 495 496 497 498 499 500

/* Change link key */
int hci_conn_change_link_key(struct hci_conn *conn)
{
	BT_DBG("conn %p", conn);

	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
		struct hci_cp_change_conn_link_key cp;
501
		cp.handle = cpu_to_le16(conn->handle);
502 503
		hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
							sizeof(cp), &cp);
L
Linus Torvalds 已提交
504
	}
505

L
Linus Torvalds 已提交
506 507 508 509 510
	return 0;
}
EXPORT_SYMBOL(hci_conn_change_link_key);

/* Switch role */
511
int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
L
Linus Torvalds 已提交
512 513 514 515 516 517 518 519 520 521
{
	BT_DBG("conn %p", conn);

	if (!role && conn->link_mode & HCI_LM_MASTER)
		return 1;

	if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) {
		struct hci_cp_switch_role cp;
		bacpy(&cp.bdaddr, &conn->dst);
		cp.role = role;
522
		hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
L
Linus Torvalds 已提交
523
	}
524

L
Linus Torvalds 已提交
525 526 527 528
	return 0;
}
EXPORT_SYMBOL(hci_conn_switch_role);

529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
/* Enter active mode */
void hci_conn_enter_active_mode(struct hci_conn *conn)
{
	struct hci_dev *hdev = conn->hdev;

	BT_DBG("conn %p mode %d", conn, conn->mode);

	if (test_bit(HCI_RAW, &hdev->flags))
		return;

	if (conn->mode != HCI_CM_SNIFF || !conn->power_save)
		goto timer;

	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
		struct hci_cp_exit_sniff_mode cp;
544
		cp.handle = cpu_to_le16(conn->handle);
545
		hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp);
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571
	}

timer:
	if (hdev->idle_timeout > 0)
		mod_timer(&conn->idle_timer,
			jiffies + msecs_to_jiffies(hdev->idle_timeout));
}

/* Enter sniff mode */
void hci_conn_enter_sniff_mode(struct hci_conn *conn)
{
	struct hci_dev *hdev = conn->hdev;

	BT_DBG("conn %p mode %d", conn, conn->mode);

	if (test_bit(HCI_RAW, &hdev->flags))
		return;

	if (!lmp_sniff_capable(hdev) || !lmp_sniff_capable(conn))
		return;

	if (conn->mode != HCI_CM_ACTIVE || !(conn->link_policy & HCI_LP_SNIFF))
		return;

	if (lmp_sniffsubr_capable(hdev) && lmp_sniffsubr_capable(conn)) {
		struct hci_cp_sniff_subrate cp;
572 573 574 575
		cp.handle             = cpu_to_le16(conn->handle);
		cp.max_latency        = cpu_to_le16(0);
		cp.min_remote_timeout = cpu_to_le16(0);
		cp.min_local_timeout  = cpu_to_le16(0);
576
		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp);
577 578 579 580
	}

	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) {
		struct hci_cp_sniff_mode cp;
581 582 583 584 585
		cp.handle       = cpu_to_le16(conn->handle);
		cp.max_interval = cpu_to_le16(hdev->sniff_max_interval);
		cp.min_interval = cpu_to_le16(hdev->sniff_min_interval);
		cp.attempt      = cpu_to_le16(4);
		cp.timeout      = cpu_to_le16(1);
586
		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp);
587 588 589
	}
}

L
Linus Torvalds 已提交
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
/* Drop all connection on the device */
void hci_conn_hash_flush(struct hci_dev *hdev)
{
	struct hci_conn_hash *h = &hdev->conn_hash;
	struct list_head *p;

	BT_DBG("hdev %s", hdev->name);

	p = h->list.next;
	while (p != &h->list) {
		struct hci_conn *c;

		c = list_entry(p, struct hci_conn, list);
		p = p->next;

		c->state = BT_CLOSED;

607
		hci_proto_disconn_cfm(c, 0x16);
L
Linus Torvalds 已提交
608 609 610 611
		hci_conn_del(c);
	}
}

612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627
/* Check pending connect attempts */
void hci_conn_check_pending(struct hci_dev *hdev)
{
	struct hci_conn *conn;

	BT_DBG("hdev %s", hdev->name);

	hci_dev_lock(hdev);

	conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);
	if (conn)
		hci_acl_connect(conn);

	hci_dev_unlock(hdev);
}

628 629 630 631 632 633 634 635 636 637 638 639 640
void hci_conn_hold_device(struct hci_conn *conn)
{
	atomic_inc(&conn->devref);
}
EXPORT_SYMBOL(hci_conn_hold_device);

void hci_conn_put_device(struct hci_conn *conn)
{
	if (atomic_dec_and_test(&conn->devref))
		hci_conn_del_sysfs(conn);
}
EXPORT_SYMBOL(hci_conn_put_device);

L
Linus Torvalds 已提交
641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
int hci_get_conn_list(void __user *arg)
{
	struct hci_conn_list_req req, *cl;
	struct hci_conn_info *ci;
	struct hci_dev *hdev;
	struct list_head *p;
	int n = 0, size, err;

	if (copy_from_user(&req, arg, sizeof(req)))
		return -EFAULT;

	if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
		return -EINVAL;

	size = sizeof(req) + req.conn_num * sizeof(*ci);

A
Andrei Emeltchenko 已提交
657 658
	cl = kmalloc(size, GFP_KERNEL);
	if (!cl)
L
Linus Torvalds 已提交
659 660
		return -ENOMEM;

A
Andrei Emeltchenko 已提交
661 662
	hdev = hci_dev_get(req.dev_id);
	if (!hdev) {
L
Linus Torvalds 已提交
663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723
		kfree(cl);
		return -ENODEV;
	}

	ci = cl->conn_info;

	hci_dev_lock_bh(hdev);
	list_for_each(p, &hdev->conn_hash.list) {
		register struct hci_conn *c;
		c = list_entry(p, struct hci_conn, list);

		bacpy(&(ci + n)->bdaddr, &c->dst);
		(ci + n)->handle = c->handle;
		(ci + n)->type  = c->type;
		(ci + n)->out   = c->out;
		(ci + n)->state = c->state;
		(ci + n)->link_mode = c->link_mode;
		if (++n >= req.conn_num)
			break;
	}
	hci_dev_unlock_bh(hdev);

	cl->dev_id = hdev->id;
	cl->conn_num = n;
	size = sizeof(req) + n * sizeof(*ci);

	hci_dev_put(hdev);

	err = copy_to_user(arg, cl, size);
	kfree(cl);

	return err ? -EFAULT : 0;
}

int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
{
	struct hci_conn_info_req req;
	struct hci_conn_info ci;
	struct hci_conn *conn;
	char __user *ptr = arg + sizeof(req);

	if (copy_from_user(&req, arg, sizeof(req)))
		return -EFAULT;

	hci_dev_lock_bh(hdev);
	conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
	if (conn) {
		bacpy(&ci.bdaddr, &conn->dst);
		ci.handle = conn->handle;
		ci.type  = conn->type;
		ci.out   = conn->out;
		ci.state = conn->state;
		ci.link_mode = conn->link_mode;
	}
	hci_dev_unlock_bh(hdev);

	if (!conn)
		return -ENOENT;

	return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
}
724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743

int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)
{
	struct hci_auth_info_req req;
	struct hci_conn *conn;

	if (copy_from_user(&req, arg, sizeof(req)))
		return -EFAULT;

	hci_dev_lock_bh(hdev);
	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);
	if (conn)
		req.type = conn->auth_type;
	hci_dev_unlock_bh(hdev);

	if (!conn)
		return -ENOENT;

	return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;
}