diff options
Diffstat (limited to 'net/bluetooth/hci_conn.c')
| -rw-r--r-- | net/bluetooth/hci_conn.c | 984 | 
1 files changed, 766 insertions, 218 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 0b1e460fe44..a7a27bc2c0b 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -24,37 +24,48 @@  /* 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> -#include <asm/uaccess.h> -#include <asm/unaligned.h> +#include <linux/export.h>  #include <net/bluetooth/bluetooth.h>  #include <net/bluetooth/hci_core.h> +#include <net/bluetooth/l2cap.h> + +#include "smp.h" +#include "a2mp.h" + +struct sco_param { +	u16 pkt_type; +	u16 max_latency; +}; + +static const struct sco_param sco_param_cvsd[] = { +	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a }, /* S3 */ +	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007 }, /* S2 */ +	{ EDR_ESCO_MASK | ESCO_EV3,   0x0007 }, /* S1 */ +	{ EDR_ESCO_MASK | ESCO_HV3,   0xffff }, /* D1 */ +	{ EDR_ESCO_MASK | ESCO_HV1,   0xffff }, /* D0 */ +}; + +static const struct sco_param sco_param_wideband[] = { +	{ EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d }, /* T2 */ +	{ EDR_ESCO_MASK | ESCO_EV3,   0x0008 }, /* T1 */ +}; + +static void hci_le_create_connection_cancel(struct hci_conn *conn) +{ +	hci_send_cmd(conn->hdev, HCI_OP_LE_CREATE_CONN_CANCEL, 0, NULL); +} -void hci_acl_connect(struct hci_conn *conn) +static void hci_acl_create_connection(struct hci_conn *conn)  {  	struct hci_dev *hdev = conn->hdev;  	struct inquiry_entry *ie;  	struct hci_cp_create_conn cp; -	BT_DBG("%p", conn); +	BT_DBG("hcon %p", conn);  	conn->state = BT_CONNECT; -	conn->out = 1; +	conn->out = true;  	conn->link_mode = HCI_LM_MASTER; @@ -66,16 +77,18 @@ void hci_acl_connect(struct hci_conn *conn)  	bacpy(&cp.bdaddr, &conn->dst);  	cp.pscan_rep_mode = 0x02; -	if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) { +	ie = hci_inquiry_cache_lookup(hdev, &conn->dst); +	if (ie) {  		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); +					    cpu_to_le16(0x8000);  		}  		memcpy(conn->dev_class, ie->data.dev_class, 3); -		conn->ssp_mode = ie->data.ssp_mode; +		if (ie->data.ssp_mode > 0) +			set_bit(HCI_CONN_SSP_ENABLED, &conn->flags);  	}  	cp.pkt_type = cpu_to_le16(conn->pkt_type); @@ -87,24 +100,34 @@ void hci_acl_connect(struct hci_conn *conn)  	hci_send_cmd(hdev, HCI_OP_CREATE_CONN, sizeof(cp), &cp);  } -static void hci_acl_connect_cancel(struct hci_conn *conn) +static void hci_acl_create_connection_cancel(struct hci_conn *conn)  {  	struct hci_cp_create_conn_cancel cp; -	BT_DBG("%p", conn); +	BT_DBG("hcon %p", conn); -	if (conn->hdev->hci_ver < 2) +	if (conn->hdev->hci_ver < BLUETOOTH_VER_1_2)  		return;  	bacpy(&cp.bdaddr, &conn->dst);  	hci_send_cmd(conn->hdev, HCI_OP_CREATE_CONN_CANCEL, sizeof(cp), &cp);  } -void hci_acl_disconn(struct hci_conn *conn, __u8 reason) +static void hci_reject_sco(struct hci_conn *conn) +{ +	struct hci_cp_reject_sync_conn_req cp; + +	cp.reason = HCI_ERROR_REMOTE_USER_TERM; +	bacpy(&cp.bdaddr, &conn->dst); + +	hci_send_cmd(conn->hdev, HCI_OP_REJECT_SYNC_CONN_REQ, sizeof(cp), &cp); +} + +void hci_disconnect(struct hci_conn *conn, __u8 reason)  {  	struct hci_cp_disconnect cp; -	BT_DBG("%p", conn); +	BT_DBG("hcon %p", conn);  	conn->state = BT_DISCONN; @@ -113,15 +136,29 @@ void hci_acl_disconn(struct hci_conn *conn, __u8 reason)  	hci_send_cmd(conn->hdev, HCI_OP_DISCONNECT, sizeof(cp), &cp);  } -void hci_add_sco(struct hci_conn *conn, __u16 handle) +static void hci_amp_disconn(struct hci_conn *conn, __u8 reason) +{ +	struct hci_cp_disconn_phy_link cp; + +	BT_DBG("hcon %p", conn); + +	conn->state = BT_DISCONN; + +	cp.phy_handle = HCI_PHY_HANDLE(conn->handle); +	cp.reason = reason; +	hci_send_cmd(conn->hdev, HCI_OP_DISCONN_PHY_LINK, +		     sizeof(cp), &cp); +} + +static 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); +	BT_DBG("hcon %p", conn);  	conn->state = BT_CONNECT; -	conn->out = 1; +	conn->out = true;  	conn->attempt++; @@ -131,28 +168,86 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)  	hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), &cp);  } -void hci_setup_sync(struct hci_conn *conn, __u16 handle) +bool hci_setup_sync(struct hci_conn *conn, __u16 handle)  {  	struct hci_dev *hdev = conn->hdev;  	struct hci_cp_setup_sync_conn cp; +	const struct sco_param *param; -	BT_DBG("%p", conn); +	BT_DBG("hcon %p", conn);  	conn->state = BT_CONNECT; -	conn->out = 1; +	conn->out = true;  	conn->attempt++;  	cp.handle   = cpu_to_le16(handle); -	cp.pkt_type = cpu_to_le16(conn->pkt_type);  	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; +	cp.voice_setting  = cpu_to_le16(conn->setting); + +	switch (conn->setting & SCO_AIRMODE_MASK) { +	case SCO_AIRMODE_TRANSP: +		if (conn->attempt > ARRAY_SIZE(sco_param_wideband)) +			return false; +		cp.retrans_effort = 0x02; +		param = &sco_param_wideband[conn->attempt - 1]; +		break; +	case SCO_AIRMODE_CVSD: +		if (conn->attempt > ARRAY_SIZE(sco_param_cvsd)) +			return false; +		cp.retrans_effort = 0x01; +		param = &sco_param_cvsd[conn->attempt - 1]; +		break; +	default: +		return false; +	} + +	cp.pkt_type = __cpu_to_le16(param->pkt_type); +	cp.max_latency = __cpu_to_le16(param->max_latency); + +	if (hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp) < 0) +		return false; -	hci_send_cmd(hdev, HCI_OP_SETUP_SYNC_CONN, sizeof(cp), &cp); +	return true; +} + +void hci_le_conn_update(struct hci_conn *conn, u16 min, u16 max, +			u16 latency, u16 to_multiplier) +{ +	struct hci_cp_le_conn_update cp; +	struct hci_dev *hdev = conn->hdev; + +	memset(&cp, 0, sizeof(cp)); + +	cp.handle		= cpu_to_le16(conn->handle); +	cp.conn_interval_min	= cpu_to_le16(min); +	cp.conn_interval_max	= cpu_to_le16(max); +	cp.conn_latency		= cpu_to_le16(latency); +	cp.supervision_timeout	= cpu_to_le16(to_multiplier); +	cp.min_ce_len		= cpu_to_le16(0x0000); +	cp.max_ce_len		= cpu_to_le16(0x0000); + +	hci_send_cmd(hdev, HCI_OP_LE_CONN_UPDATE, sizeof(cp), &cp); +} + +void hci_le_start_enc(struct hci_conn *conn, __le16 ediv, __le64 rand, +		      __u8 ltk[16]) +{ +	struct hci_dev *hdev = conn->hdev; +	struct hci_cp_le_start_enc cp; + +	BT_DBG("hcon %p", conn); + +	memset(&cp, 0, sizeof(cp)); + +	cp.handle = cpu_to_le16(conn->handle); +	cp.rand = rand; +	cp.ediv = ediv; +	memcpy(cp.ltk, ltk, sizeof(cp.ltk)); + +	hci_send_cmd(hdev, HCI_OP_LE_START_ENC, sizeof(cp), &cp);  }  /* Device _must_ be locked */ @@ -160,11 +255,11 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)  {  	struct hci_conn *sco = conn->link; -	BT_DBG("%p", conn); -  	if (!sco)  		return; +	BT_DBG("hcon %p", conn); +  	if (!status) {  		if (lmp_esco_capable(conn->hdev))  			hci_setup_sync(sco, conn->handle); @@ -176,71 +271,167 @@ void hci_sco_setup(struct hci_conn *conn, __u8 status)  	}  } -static void hci_conn_timeout(unsigned long arg) +static void hci_conn_disconnect(struct hci_conn *conn)  { -	struct hci_conn *conn = (void *) arg; -	struct hci_dev *hdev = conn->hdev; -	__u8 reason; +	__u8 reason = hci_proto_disconn_ind(conn); -	BT_DBG("conn %p state %d", conn, conn->state); +	switch (conn->type) { +	case AMP_LINK: +		hci_amp_disconn(conn, reason); +		break; +	default: +		hci_disconnect(conn, reason); +		break; +	} +} -	if (atomic_read(&conn->refcnt)) +static void hci_conn_timeout(struct work_struct *work) +{ +	struct hci_conn *conn = container_of(work, struct hci_conn, +					     disc_work.work); +	int refcnt = atomic_read(&conn->refcnt); + +	BT_DBG("hcon %p state %s", conn, state_to_string(conn->state)); + +	WARN_ON(refcnt < 0); + +	/* FIXME: It was observed that in pairing failed scenario, refcnt +	 * drops below 0. Probably this is because l2cap_conn_del calls +	 * l2cap_chan_del for each channel, and inside l2cap_chan_del conn is +	 * dropped. After that loop hci_chan_del is called which also drops +	 * conn. For now make sure that ACL is alive if refcnt is higher then 0, +	 * otherwise drop it. +	 */ +	if (refcnt > 0)  		return; -	hci_dev_lock(hdev); -  	switch (conn->state) {  	case BT_CONNECT:  	case BT_CONNECT2: -		if (conn->type == ACL_LINK && conn->out) -			hci_acl_connect_cancel(conn); +		if (conn->out) { +			if (conn->type == ACL_LINK) +				hci_acl_create_connection_cancel(conn); +			else if (conn->type == LE_LINK) +				hci_le_create_connection_cancel(conn); +		} else if (conn->type == SCO_LINK || conn->type == ESCO_LINK) { +			hci_reject_sco(conn); +		}  		break;  	case BT_CONFIG:  	case BT_CONNECTED: -		reason = hci_proto_disconn_ind(conn); -		hci_acl_disconn(conn, reason); +		hci_conn_disconnect(conn);  		break;  	default:  		conn->state = BT_CLOSED;  		break;  	} +} -	hci_dev_unlock(hdev); +/* Enter sniff mode */ +static void hci_conn_idle(struct work_struct *work) +{ +	struct hci_conn *conn = container_of(work, struct hci_conn, +					     idle_work.work); +	struct hci_dev *hdev = conn->hdev; + +	BT_DBG("hcon %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; +		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); +		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); +	} + +	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) { +		struct hci_cp_sniff_mode cp; +		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); +		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp); +	} +} + +static void hci_conn_auto_accept(struct work_struct *work) +{ +	struct hci_conn *conn = container_of(work, struct hci_conn, +					     auto_accept_work.work); + +	hci_send_cmd(conn->hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), +		     &conn->dst);  } -static void hci_conn_idle(unsigned long arg) +static void le_conn_timeout(struct work_struct *work)  { -	struct hci_conn *conn = (void *) arg; +	struct hci_conn *conn = container_of(work, struct hci_conn, +					     le_conn_timeout.work); +	struct hci_dev *hdev = conn->hdev; -	BT_DBG("conn %p mode %d", conn, conn->mode); +	BT_DBG(""); + +	/* We could end up here due to having done directed advertising, +	 * so clean up the state if necessary. This should however only +	 * happen with broken hardware or if low duty cycle was used +	 * (which doesn't have a timeout of its own). +	 */ +	if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { +		u8 enable = 0x00; +		hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), +			     &enable); +		hci_le_conn_failed(conn, HCI_ERROR_ADVERTISING_TIMEOUT); +		return; +	} -	hci_conn_enter_sniff_mode(conn); +	hci_le_create_connection_cancel(conn);  }  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)); +	BT_DBG("%s dst %pMR", hdev->name, dst); -	conn = kzalloc(sizeof(struct hci_conn), GFP_ATOMIC); +	conn = kzalloc(sizeof(struct hci_conn), GFP_KERNEL);  	if (!conn)  		return NULL;  	bacpy(&conn->dst, dst); +	bacpy(&conn->src, &hdev->bdaddr);  	conn->hdev  = hdev;  	conn->type  = type;  	conn->mode  = HCI_CM_ACTIVE;  	conn->state = BT_OPEN;  	conn->auth_type = HCI_AT_GENERAL_BONDING; +	conn->io_capability = hdev->io_capability; +	conn->remote_auth = 0xff; +	conn->key_type = 0xff; +	conn->tx_power = HCI_TX_POWER_INVALID; +	conn->max_tx_power = HCI_TX_POWER_INVALID; -	conn->power_save = 1; +	set_bit(HCI_CONN_POWER_SAVE, &conn->flags);  	conn->disc_timeout = HCI_DISCONN_TIMEOUT;  	switch (type) {  	case ACL_LINK:  		conn->pkt_type = hdev->pkt_type & ACL_PTYPE_MASK;  		break; +	case LE_LINK: +		/* conn->src should reflect the local identity address */ +		hci_copy_identity_address(hdev, &conn->src, &conn->src_type); +		break;  	case SCO_LINK:  		if (lmp_esco_capable(hdev))  			conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) | @@ -255,25 +446,23 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)  	skb_queue_head_init(&conn->data_q); -	setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn); -	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); +	INIT_LIST_HEAD(&conn->chan_list); + +	INIT_DELAYED_WORK(&conn->disc_work, hci_conn_timeout); +	INIT_DELAYED_WORK(&conn->auto_accept_work, hci_conn_auto_accept); +	INIT_DELAYED_WORK(&conn->idle_work, hci_conn_idle); +	INIT_DELAYED_WORK(&conn->le_conn_timeout, le_conn_timeout);  	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); -	atomic_set(&conn->devref, 0); -  	hci_conn_init_sysfs(conn); -	tasklet_enable(&hdev->tx_task); -  	return conn;  } @@ -281,11 +470,11 @@ 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); - -	del_timer(&conn->idle_timer); +	BT_DBG("%s hcon %p handle %d", hdev->name, conn, conn->handle); -	del_timer(&conn->disc_timer); +	cancel_delayed_work_sync(&conn->disc_work); +	cancel_delayed_work_sync(&conn->auto_accept_work); +	cancel_delayed_work_sync(&conn->idle_work);  	if (conn->type == ACL_LINK) {  		struct hci_conn *sco = conn->link; @@ -294,45 +483,55 @@ int hci_conn_del(struct hci_conn *conn)  		/* Unacked frames */  		hdev->acl_cnt += conn->sent; +	} else if (conn->type == LE_LINK) { +		cancel_delayed_work_sync(&conn->le_conn_timeout); + +		if (hdev->le_pkts) +			hdev->le_cnt += conn->sent; +		else +			hdev->acl_cnt += conn->sent;  	} else {  		struct hci_conn *acl = conn->link;  		if (acl) {  			acl->link = NULL; -			hci_conn_put(acl); +			hci_conn_drop(acl);  		}  	} -	tasklet_disable(&hdev->tx_task); +	hci_chan_list_flush(conn); + +	if (conn->amp_mgr) +		amp_mgr_put(conn->amp_mgr);  	hci_conn_hash_del(hdev, conn);  	if (hdev->notify)  		hdev->notify(hdev, HCI_NOTIFY_CONN_DEL); -	tasklet_enable(&hdev->tx_task); -  	skb_queue_purge(&conn->data_q); -	hci_conn_put_device(conn); +	hci_conn_del_sysfs(conn);  	hci_dev_put(hdev); +	hci_conn_put(conn); +  	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)); +	struct hci_dev *hdev = NULL, *d; -	read_lock_bh(&hci_dev_list_lock); +	BT_DBG("%pMR -> %pMR", src, dst); -	list_for_each(p, &hci_dev_list) { -		struct hci_dev *d = list_entry(p, struct hci_dev, list); +	read_lock(&hci_dev_list_lock); -		if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags)) +	list_for_each_entry(d, &hci_dev_list, list) { +		if (!test_bit(HCI_UP, &d->flags) || +		    test_bit(HCI_RAW, &d->flags) || +		    test_bit(HCI_USER_CHANNEL, &d->dev_flags) || +		    d->dev_type != HCI_BREDR)  			continue;  		/* Simple routing: @@ -354,45 +553,275 @@ struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)  	if (hdev)  		hdev = hci_dev_hold(hdev); -	read_unlock_bh(&hci_dev_list_lock); +	read_unlock(&hci_dev_list_lock);  	return hdev;  }  EXPORT_SYMBOL(hci_get_route); -/* Create SCO or ACL connection. - * Device _must_ be locked */ -struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type) +/* This function requires the caller holds hdev->lock */ +void hci_le_conn_failed(struct hci_conn *conn, u8 status) +{ +	struct hci_dev *hdev = conn->hdev; + +	conn->state = BT_CLOSED; + +	mgmt_connect_failed(hdev, &conn->dst, conn->type, conn->dst_type, +			    status); + +	hci_proto_connect_cfm(conn, status); + +	hci_conn_del(conn); + +	/* Since we may have temporarily stopped the background scanning in +	 * favor of connection establishment, we should restart it. +	 */ +	hci_update_background_scan(hdev); + +	/* Re-enable advertising in case this was a failed connection +	 * attempt as a peripheral. +	 */ +	mgmt_reenable_advertising(hdev); +} + +static void create_le_conn_complete(struct hci_dev *hdev, u8 status) +{ +	struct hci_conn *conn; + +	if (status == 0) +		return; + +	BT_ERR("HCI request failed to create LE connection: status 0x%2.2x", +	       status); + +	hci_dev_lock(hdev); + +	conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); +	if (!conn) +		goto done; + +	hci_le_conn_failed(conn, status); + +done: +	hci_dev_unlock(hdev); +} + +static void hci_req_add_le_create_conn(struct hci_request *req, +				       struct hci_conn *conn) +{ +	struct hci_cp_le_create_conn cp; +	struct hci_dev *hdev = conn->hdev; +	u8 own_addr_type; + +	memset(&cp, 0, sizeof(cp)); + +	/* Update random address, but set require_privacy to false so +	 * that we never connect with an unresolvable address. +	 */ +	if (hci_update_random_address(req, false, &own_addr_type)) +		return; + +	cp.scan_interval = cpu_to_le16(hdev->le_scan_interval); +	cp.scan_window = cpu_to_le16(hdev->le_scan_window); +	bacpy(&cp.peer_addr, &conn->dst); +	cp.peer_addr_type = conn->dst_type; +	cp.own_address_type = own_addr_type; +	cp.conn_interval_min = cpu_to_le16(conn->le_conn_min_interval); +	cp.conn_interval_max = cpu_to_le16(conn->le_conn_max_interval); +	cp.supervision_timeout = cpu_to_le16(0x002a); +	cp.min_ce_len = cpu_to_le16(0x0000); +	cp.max_ce_len = cpu_to_le16(0x0000); + +	hci_req_add(req, HCI_OP_LE_CREATE_CONN, sizeof(cp), &cp); + +	conn->state = BT_CONNECT; +} + +static void hci_req_directed_advertising(struct hci_request *req, +					 struct hci_conn *conn) +{ +	struct hci_dev *hdev = req->hdev; +	struct hci_cp_le_set_adv_param cp; +	u8 own_addr_type; +	u8 enable; + +	enable = 0x00; +	hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); + +	/* Clear the HCI_ADVERTISING bit temporarily so that the +	 * hci_update_random_address knows that it's safe to go ahead +	 * and write a new random address. The flag will be set back on +	 * as soon as the SET_ADV_ENABLE HCI command completes. +	 */ +	clear_bit(HCI_ADVERTISING, &hdev->dev_flags); + +	/* Set require_privacy to false so that the remote device has a +	 * chance of identifying us. +	 */ +	if (hci_update_random_address(req, false, &own_addr_type) < 0) +		return; + +	memset(&cp, 0, sizeof(cp)); +	cp.type = LE_ADV_DIRECT_IND; +	cp.own_address_type = own_addr_type; +	cp.direct_addr_type = conn->dst_type; +	bacpy(&cp.direct_addr, &conn->dst); +	cp.channel_map = hdev->le_adv_channel_map; + +	hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp); + +	enable = 0x01; +	hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable); + +	conn->state = BT_CONNECT; +} + +struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst, +				u8 dst_type, u8 sec_level, u8 auth_type) +{ +	struct hci_conn_params *params; +	struct hci_conn *conn; +	struct smp_irk *irk; +	struct hci_request req; +	int err; + +	/* Some devices send ATT messages as soon as the physical link is +	 * established. To be able to handle these ATT messages, the user- +	 * space first establishes the connection and then starts the pairing +	 * process. +	 * +	 * So if a hci_conn object already exists for the following connection +	 * attempt, we simply update pending_sec_level and auth_type fields +	 * and return the object found. +	 */ +	conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst); +	if (conn) { +		conn->pending_sec_level = sec_level; +		conn->auth_type = auth_type; +		goto done; +	} + +	/* Since the controller supports only one LE connection attempt at a +	 * time, we return -EBUSY if there is any connection attempt running. +	 */ +	conn = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT); +	if (conn) +		return ERR_PTR(-EBUSY); + +	/* When given an identity address with existing identity +	 * resolving key, the connection needs to be established +	 * to a resolvable random address. +	 * +	 * This uses the cached random resolvable address from +	 * a previous scan. When no cached address is available, +	 * try connecting to the identity address instead. +	 * +	 * Storing the resolvable random address is required here +	 * to handle connection failures. The address will later +	 * be resolved back into the original identity address +	 * from the connect request. +	 */ +	irk = hci_find_irk_by_addr(hdev, dst, dst_type); +	if (irk && bacmp(&irk->rpa, BDADDR_ANY)) { +		dst = &irk->rpa; +		dst_type = ADDR_LE_DEV_RANDOM; +	} + +	conn = hci_conn_add(hdev, LE_LINK, dst); +	if (!conn) +		return ERR_PTR(-ENOMEM); + +	conn->dst_type = dst_type; +	conn->sec_level = BT_SECURITY_LOW; +	conn->pending_sec_level = sec_level; +	conn->auth_type = auth_type; + +	hci_req_init(&req, hdev); + +	if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) { +		hci_req_directed_advertising(&req, conn); +		goto create_conn; +	} + +	conn->out = true; +	conn->link_mode |= HCI_LM_MASTER; + +	params = hci_conn_params_lookup(hdev, &conn->dst, conn->dst_type); +	if (params) { +		conn->le_conn_min_interval = params->conn_min_interval; +		conn->le_conn_max_interval = params->conn_max_interval; +	} else { +		conn->le_conn_min_interval = hdev->le_conn_min_interval; +		conn->le_conn_max_interval = hdev->le_conn_max_interval; +	} + +	/* If controller is scanning, we stop it since some controllers are +	 * not able to scan and connect at the same time. Also set the +	 * HCI_LE_SCAN_INTERRUPTED flag so that the command complete +	 * handler for scan disabling knows to set the correct discovery +	 * state. +	 */ +	if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) { +		hci_req_add_le_scan_disable(&req); +		set_bit(HCI_LE_SCAN_INTERRUPTED, &hdev->dev_flags); +	} + +	hci_req_add_le_create_conn(&req, conn); + +create_conn: +	err = hci_req_run(&req, create_le_conn_complete); +	if (err) { +		hci_conn_del(conn); +		return ERR_PTR(err); +	} + +done: +	hci_conn_hold(conn); +	return conn; +} + +struct hci_conn *hci_connect_acl(struct hci_dev *hdev, bdaddr_t *dst, +				 u8 sec_level, u8 auth_type)  {  	struct hci_conn *acl; -	struct hci_conn *sco; -	BT_DBG("%s dst %s", hdev->name, batostr(dst)); +	if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) +		return ERR_PTR(-ENOTSUPP); -	if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) { -		if (!(acl = hci_conn_add(hdev, ACL_LINK, dst))) -			return NULL; +	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst); +	if (!acl) { +		acl = hci_conn_add(hdev, ACL_LINK, dst); +		if (!acl) +			return ERR_PTR(-ENOMEM);  	}  	hci_conn_hold(acl);  	if (acl->state == BT_OPEN || acl->state == BT_CLOSED) { -		acl->sec_level = sec_level; +		acl->sec_level = BT_SECURITY_LOW; +		acl->pending_sec_level = sec_level;  		acl->auth_type = auth_type; -		hci_acl_connect(acl); -	} else { -		if (acl->sec_level < sec_level) -			acl->sec_level = sec_level; -		if (acl->auth_type < auth_type) -			acl->auth_type = auth_type; +		hci_acl_create_connection(acl);  	} -	if (type == ACL_LINK) +	return acl; +} + +struct hci_conn *hci_connect_sco(struct hci_dev *hdev, int type, bdaddr_t *dst, +				 __u16 setting) +{ +	struct hci_conn *acl; +	struct hci_conn *sco; + +	acl = hci_connect_acl(hdev, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING); +	if (IS_ERR(acl))  		return acl; -	if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) { -		if (!(sco = hci_conn_add(hdev, type, dst))) { -			hci_conn_put(acl); -			return NULL; +	sco = hci_conn_hash_lookup_ba(hdev, type, dst); +	if (!sco) { +		sco = hci_conn_add(hdev, type, dst); +		if (!sco) { +			hci_conn_drop(acl); +			return ERR_PTR(-ENOMEM);  		}  	} @@ -401,14 +830,16 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8  	hci_conn_hold(sco); +	sco->setting = setting; +  	if (acl->state == BT_CONNECTED && -			(sco->state == BT_OPEN || sco->state == BT_CLOSED)) { -		acl->power_save = 1; -		hci_conn_enter_active_mode(acl); +	    (sco->state == BT_OPEN || sco->state == BT_CLOSED)) { +		set_bit(HCI_CONN_POWER_SAVE, &acl->flags); +		hci_conn_enter_active_mode(acl, BT_POWER_FORCE_ACTIVE_ON); -		if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->pend)) { +		if (test_bit(HCI_CONN_MODE_CHANGE_PEND, &acl->flags)) {  			/* defer SCO setup until mode change completed */ -			set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->pend); +			set_bit(HCI_CONN_SCO_SETUP_PEND, &acl->flags);  			return sco;  		} @@ -417,98 +848,189 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8  	return sco;  } -EXPORT_SYMBOL(hci_connect);  /* Check link security requirement */  int hci_conn_check_link_mode(struct hci_conn *conn)  { -	BT_DBG("conn %p", conn); +	BT_DBG("hcon %p", conn); + +	/* In Secure Connections Only mode, it is required that Secure +	 * Connections is used and the link is encrypted with AES-CCM +	 * using a P-256 authenticated combination key. +	 */ +	if (test_bit(HCI_SC_ONLY, &conn->hdev->flags)) { +		if (!hci_conn_sc_enabled(conn) || +		    !test_bit(HCI_CONN_AES_CCM, &conn->flags) || +		    conn->key_type != HCI_LK_AUTH_COMBINATION_P256) +			return 0; +	} -	if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0 && -					!(conn->link_mode & HCI_LM_ENCRYPT)) +	if (hci_conn_ssp_enabled(conn) && !(conn->link_mode & HCI_LM_ENCRYPT))  		return 0;  	return 1;  } -EXPORT_SYMBOL(hci_conn_check_link_mode);  /* Authenticate remote device */  static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)  { -	BT_DBG("conn %p", conn); +	BT_DBG("hcon %p", conn); + +	if (conn->pending_sec_level > sec_level) +		sec_level = conn->pending_sec_level;  	if (sec_level > conn->sec_level) -		conn->sec_level = sec_level; +		conn->pending_sec_level = sec_level;  	else if (conn->link_mode & HCI_LM_AUTH)  		return 1; +	/* Make sure we preserve an existing MITM requirement*/ +	auth_type |= (conn->auth_type & 0x01); +  	conn->auth_type = auth_type; -	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { +	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {  		struct hci_cp_auth_requested cp; +  		cp.handle = cpu_to_le16(conn->handle);  		hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED, -							sizeof(cp), &cp); +			     sizeof(cp), &cp); + +		/* If we're already encrypted set the REAUTH_PEND flag, +		 * otherwise set the ENCRYPT_PEND. +		 */ +		if (conn->link_mode & HCI_LM_ENCRYPT) +			set_bit(HCI_CONN_REAUTH_PEND, &conn->flags); +		else +			set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);  	}  	return 0;  } +/* Encrypt the the link */ +static void hci_conn_encrypt(struct hci_conn *conn) +{ +	BT_DBG("hcon %p", conn); + +	if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) { +		struct hci_cp_set_conn_encrypt cp; +		cp.handle  = cpu_to_le16(conn->handle); +		cp.encrypt = 0x01; +		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, sizeof(cp), +			     &cp); +	} +} +  /* Enable security */  int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)  { -	BT_DBG("conn %p", conn); +	BT_DBG("hcon %p", conn); +	if (conn->type == LE_LINK) +		return smp_conn_security(conn, sec_level); + +	/* For sdp we don't need the link key. */  	if (sec_level == BT_SECURITY_SDP)  		return 1; -	if (sec_level == BT_SECURITY_LOW && -				(!conn->ssp_mode || !conn->hdev->ssp_mode)) +	/* For non 2.1 devices and low security level we don't need the link +	   key. */ +	if (sec_level == BT_SECURITY_LOW && !hci_conn_ssp_enabled(conn))  		return 1; -	if (conn->link_mode & HCI_LM_ENCRYPT) -		return hci_conn_auth(conn, sec_level, auth_type); +	/* For other security levels we need the link key. */ +	if (!(conn->link_mode & HCI_LM_AUTH)) +		goto auth; + +	/* An authenticated FIPS approved combination key has sufficient +	 * security for security level 4. */ +	if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 && +	    sec_level == BT_SECURITY_FIPS) +		goto encrypt; + +	/* An authenticated combination key has sufficient security for +	   security level 3. */ +	if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 || +	     conn->key_type == HCI_LK_AUTH_COMBINATION_P256) && +	    sec_level == BT_SECURITY_HIGH) +		goto encrypt; + +	/* An unauthenticated combination key has sufficient security for +	   security level 1 and 2. */ +	if ((conn->key_type == HCI_LK_UNAUTH_COMBINATION_P192 || +	     conn->key_type == HCI_LK_UNAUTH_COMBINATION_P256) && +	    (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW)) +		goto encrypt; + +	/* A combination key has always sufficient security for the security +	   levels 1 or 2. High security level requires the combination key +	   is generated using maximum PIN code length (16). +	   For pre 2.1 units. */ +	if (conn->key_type == HCI_LK_COMBINATION && +	    (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW || +	     conn->pin_length == 16)) +		goto encrypt; + +auth: +	if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags)) +		return 0; -	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) +	if (!hci_conn_auth(conn, sec_level, auth_type))  		return 0; -	if (hci_conn_auth(conn, sec_level, auth_type)) { -		struct hci_cp_set_conn_encrypt cp; -		cp.handle  = cpu_to_le16(conn->handle); -		cp.encrypt = 1; -		hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT, -							sizeof(cp), &cp); -	} +encrypt: +	if (conn->link_mode & HCI_LM_ENCRYPT) +		return 1; +	hci_conn_encrypt(conn);  	return 0;  }  EXPORT_SYMBOL(hci_conn_security); +/* Check secure link requirement */ +int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level) +{ +	BT_DBG("hcon %p", conn); + +	/* Accept if non-secure or higher security level is required */ +	if (sec_level != BT_SECURITY_HIGH && sec_level != BT_SECURITY_FIPS) +		return 1; + +	/* Accept if secure or higher security level is already present */ +	if (conn->sec_level == BT_SECURITY_HIGH || +	    conn->sec_level == BT_SECURITY_FIPS) +		return 1; + +	/* Reject not secure link */ +	return 0; +} +EXPORT_SYMBOL(hci_conn_check_secure); +  /* Change link key */  int hci_conn_change_link_key(struct hci_conn *conn)  { -	BT_DBG("conn %p", conn); +	BT_DBG("hcon %p", conn); -	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) { +	if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {  		struct hci_cp_change_conn_link_key cp;  		cp.handle = cpu_to_le16(conn->handle);  		hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY, -							sizeof(cp), &cp); +			     sizeof(cp), &cp);  	}  	return 0;  } -EXPORT_SYMBOL(hci_conn_change_link_key);  /* Switch role */  int hci_conn_switch_role(struct hci_conn *conn, __u8 role)  { -	BT_DBG("conn %p", conn); +	BT_DBG("hcon %p", conn);  	if (!role && conn->link_mode & HCI_LM_MASTER)  		return 1; -	if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) { +	if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->flags)) {  		struct hci_cp_switch_role cp;  		bacpy(&cp.bdaddr, &conn->dst);  		cp.role = role; @@ -520,19 +1042,22 @@ int hci_conn_switch_role(struct hci_conn *conn, __u8 role)  EXPORT_SYMBOL(hci_conn_switch_role);  /* Enter active mode */ -void hci_conn_enter_active_mode(struct hci_conn *conn) +void hci_conn_enter_active_mode(struct hci_conn *conn, __u8 force_active)  {  	struct hci_dev *hdev = conn->hdev; -	BT_DBG("conn %p mode %d", conn, conn->mode); +	BT_DBG("hcon %p mode %d", conn, conn->mode);  	if (test_bit(HCI_RAW, &hdev->flags))  		return; -	if (conn->mode != HCI_CM_SNIFF || !conn->power_save) +	if (conn->mode != HCI_CM_SNIFF) +		goto timer; + +	if (!test_bit(HCI_CONN_POWER_SAVE, &conn->flags) && !force_active)  		goto timer; -	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { +	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->flags)) {  		struct hci_cp_exit_sniff_mode cp;  		cp.handle = cpu_to_le16(conn->handle);  		hci_send_cmd(hdev, HCI_OP_EXIT_SNIFF_MODE, sizeof(cp), &cp); @@ -540,64 +1065,22 @@ void hci_conn_enter_active_mode(struct hci_conn *conn)  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; -		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); -		hci_send_cmd(hdev, HCI_OP_SNIFF_SUBRATE, sizeof(cp), &cp); -	} - -	if (!test_and_set_bit(HCI_CONN_MODE_CHANGE_PEND, &conn->pend)) { -		struct hci_cp_sniff_mode cp; -		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); -		hci_send_cmd(hdev, HCI_OP_SNIFF_MODE, sizeof(cp), &cp); -	} +		queue_delayed_work(hdev->workqueue, &conn->idle_work, +				   msecs_to_jiffies(hdev->idle_timeout));  }  /* 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; +	struct hci_conn *c, *n;  	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; - +	list_for_each_entry_safe(c, n, &h->list, list) {  		c->state = BT_CLOSED; -		hci_proto_disconn_cfm(c, 0x16); +		hci_proto_disconn_cfm(c, HCI_ERROR_LOCAL_HOST_TERM);  		hci_conn_del(c);  	}  } @@ -613,30 +1096,17 @@ void hci_conn_check_pending(struct hci_dev *hdev)  	conn = hci_conn_hash_lookup_state(hdev, ACL_LINK, BT_CONNECT2);  	if (conn) -		hci_acl_connect(conn); +		hci_acl_create_connection(conn);  	hci_dev_unlock(hdev);  } -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); -  int hci_get_conn_list(void __user *arg)  { +	struct hci_conn *c;  	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))) @@ -647,21 +1117,20 @@ int hci_get_conn_list(void __user *arg)  	size = sizeof(req) + req.conn_num * sizeof(*ci); -	if (!(cl = kmalloc(size, GFP_KERNEL))) +	cl = kmalloc(size, GFP_KERNEL); +	if (!cl)  		return -ENOMEM; -	if (!(hdev = hci_dev_get(req.dev_id))) { +	hdev = hci_dev_get(req.dev_id); +	if (!hdev) {  		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); - +	hci_dev_lock(hdev); +	list_for_each_entry(c, &hdev->conn_hash.list, list) {  		bacpy(&(ci + n)->bdaddr, &c->dst);  		(ci + n)->handle = c->handle;  		(ci + n)->type  = c->type; @@ -671,7 +1140,7 @@ int hci_get_conn_list(void __user *arg)  		if (++n >= req.conn_num)  			break;  	} -	hci_dev_unlock_bh(hdev); +	hci_dev_unlock(hdev);  	cl->dev_id = hdev->id;  	cl->conn_num = n; @@ -695,7 +1164,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)  	if (copy_from_user(&req, arg, sizeof(req)))  		return -EFAULT; -	hci_dev_lock_bh(hdev); +	hci_dev_lock(hdev);  	conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);  	if (conn) {  		bacpy(&ci.bdaddr, &conn->dst); @@ -705,7 +1174,7 @@ int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)  		ci.state = conn->state;  		ci.link_mode = conn->link_mode;  	} -	hci_dev_unlock_bh(hdev); +	hci_dev_unlock(hdev);  	if (!conn)  		return -ENOENT; @@ -721,14 +1190,93 @@ int hci_get_auth_info(struct hci_dev *hdev, void __user *arg)  	if (copy_from_user(&req, arg, sizeof(req)))  		return -EFAULT; -	hci_dev_lock_bh(hdev); +	hci_dev_lock(hdev);  	conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &req.bdaddr);  	if (conn)  		req.type = conn->auth_type; -	hci_dev_unlock_bh(hdev); +	hci_dev_unlock(hdev);  	if (!conn)  		return -ENOENT;  	return copy_to_user(arg, &req, sizeof(req)) ? -EFAULT : 0;  } + +struct hci_chan *hci_chan_create(struct hci_conn *conn) +{ +	struct hci_dev *hdev = conn->hdev; +	struct hci_chan *chan; + +	BT_DBG("%s hcon %p", hdev->name, conn); + +	chan = kzalloc(sizeof(struct hci_chan), GFP_KERNEL); +	if (!chan) +		return NULL; + +	chan->conn = conn; +	skb_queue_head_init(&chan->data_q); +	chan->state = BT_CONNECTED; + +	list_add_rcu(&chan->list, &conn->chan_list); + +	return chan; +} + +void hci_chan_del(struct hci_chan *chan) +{ +	struct hci_conn *conn = chan->conn; +	struct hci_dev *hdev = conn->hdev; + +	BT_DBG("%s hcon %p chan %p", hdev->name, conn, chan); + +	list_del_rcu(&chan->list); + +	synchronize_rcu(); + +	hci_conn_drop(conn); + +	skb_queue_purge(&chan->data_q); +	kfree(chan); +} + +void hci_chan_list_flush(struct hci_conn *conn) +{ +	struct hci_chan *chan, *n; + +	BT_DBG("hcon %p", conn); + +	list_for_each_entry_safe(chan, n, &conn->chan_list, list) +		hci_chan_del(chan); +} + +static struct hci_chan *__hci_chan_lookup_handle(struct hci_conn *hcon, +						 __u16 handle) +{ +	struct hci_chan *hchan; + +	list_for_each_entry(hchan, &hcon->chan_list, list) { +		if (hchan->handle == handle) +			return hchan; +	} + +	return NULL; +} + +struct hci_chan *hci_chan_lookup_handle(struct hci_dev *hdev, __u16 handle) +{ +	struct hci_conn_hash *h = &hdev->conn_hash; +	struct hci_conn *hcon; +	struct hci_chan *hchan = NULL; + +	rcu_read_lock(); + +	list_for_each_entry_rcu(hcon, &h->list, list) { +		hchan = __hci_chan_lookup_handle(hcon, handle); +		if (hchan) +			break; +	} + +	rcu_read_unlock(); + +	return hchan; +}  | 
