diff options
| author | David S. Miller <davem@davemloft.net> | 2011-05-05 14:09:28 -0700 | 
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-05-05 14:09:28 -0700 | 
| commit | 90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2 (patch) | |
| tree | 6951c8d0e529dbfc7c4cec75d4cec63350e39b7c /net/bluetooth/hci_conn.c | |
| parent | 228e548e602061b08ee8e8966f567c12aa079682 (diff) | |
| parent | a70171dce9cd44cb06c7d299eba9fa87a8933045 (diff) | |
| download | olio-linux-3.10-90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2.tar.xz olio-linux-3.10-90864fbc7639d7a2300c67a18c9fb9fbcf7d51d2.zip  | |
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next-2.6
Diffstat (limited to 'net/bluetooth/hci_conn.c')
| -rw-r--r-- | net/bluetooth/hci_conn.c | 76 | 
1 files changed, 67 insertions, 9 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7a6f56b2f49..7f5ad8a2b22 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -269,6 +269,19 @@ static void hci_conn_idle(unsigned long arg)  	hci_conn_enter_sniff_mode(conn);  } +static void hci_conn_auto_accept(unsigned long arg) +{ +	struct hci_conn *conn = (void *) arg; +	struct hci_dev *hdev = conn->hdev; + +	hci_dev_lock(hdev); + +	hci_send_cmd(hdev, HCI_OP_USER_CONFIRM_REPLY, sizeof(conn->dst), +								&conn->dst); + +	hci_dev_unlock(hdev); +} +  struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)  {  	struct hci_conn *conn; @@ -287,6 +300,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)  	conn->auth_type = HCI_AT_GENERAL_BONDING;  	conn->io_capability = hdev->io_capability;  	conn->remote_auth = 0xff; +	conn->key_type = 0xff;  	conn->power_save = 1;  	conn->disc_timeout = HCI_DISCONN_TIMEOUT; @@ -311,6 +325,8 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)  	setup_timer(&conn->disc_timer, hci_conn_timeout, (unsigned long)conn);  	setup_timer(&conn->idle_timer, hci_conn_idle, (unsigned long)conn); +	setup_timer(&conn->auto_accept_timer, hci_conn_auto_accept, +							(unsigned long) conn);  	atomic_set(&conn->refcnt, 0); @@ -341,6 +357,8 @@ int hci_conn_del(struct hci_conn *conn)  	del_timer(&conn->disc_timer); +	del_timer(&conn->auto_accept_timer); +  	if (conn->type == ACL_LINK) {  		struct hci_conn *sco = conn->link;  		if (sco) @@ -535,32 +553,72 @@ static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)  	return 0;  } +/* Encrypt the the link */ +static void hci_conn_encrypt(struct hci_conn *conn) +{ +	BT_DBG("conn %p", conn); + +	if (!test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) { +		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); +	/* For sdp we don't need the link key. */  	if (sec_level == BT_SECURITY_SDP)  		return 1; +	/* For non 2.1 devices and low security level we don't need the link +	   key. */  	if (sec_level == BT_SECURITY_LOW &&  				(!conn->ssp_mode || !conn->hdev->ssp_mode))  		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 combination key has sufficient security for any +	   security level. */ +	if (conn->key_type == HCI_LK_AUTH_COMBINATION) +		goto encrypt; + +	/* An unauthenticated combination key has sufficient security for +	   security level 1 and 2. */ +	if (conn->key_type == HCI_LK_UNAUTH_COMBINATION && +			(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_HIGH || +			conn->pin_length == 16)) +		goto encrypt; + +auth:  	if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))  		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); -	} +	hci_conn_auth(conn, sec_level, auth_type); +	return 0; + +encrypt: +	if (conn->link_mode & HCI_LM_ENCRYPT) +		return 1; +	hci_conn_encrypt(conn);  	return 0;  }  EXPORT_SYMBOL(hci_conn_security);  |