diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 13:43:21 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-05-20 13:43:21 -0700 |
commit | 06f4e926d256d902dd9a53dcb400fd74974ce087 (patch) | |
tree | 0b438b67f5f0eff6fd617bc497a9dace6164a488 /net/bluetooth/hci_conn.c | |
parent | 8e7bfcbab3825d1b404d615cb1b54f44ff81f981 (diff) | |
parent | d93515611bbc70c2fe4db232e5feb448ed8e4cc9 (diff) | |
download | linux-stable-06f4e926d256d902dd9a53dcb400fd74974ce087.tar.gz |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next-2.6: (1446 commits)
macvlan: fix panic if lowerdev in a bond
tg3: Add braces around 5906 workaround.
tg3: Fix NETIF_F_LOOPBACK error
macvlan: remove one synchronize_rcu() call
networking: NET_CLS_ROUTE4 depends on INET
irda: Fix error propagation in ircomm_lmp_connect_response()
irda: Kill set but unused variable 'bytes' in irlan_check_command_param()
irda: Kill set but unused variable 'clen' in ircomm_connect_indication()
rxrpc: Fix set but unused variable 'usage' in rxrpc_get_transport()
be2net: Kill set but unused variable 'req' in lancer_fw_download()
irda: Kill set but unused vars 'saddr' and 'daddr' in irlan_provider_connect_indication()
atl1c: atl1c_resume() is only used when CONFIG_PM_SLEEP is defined.
rxrpc: Fix set but unused variable 'usage' in rxrpc_get_peer().
rxrpc: Kill set but unused variable 'local' in rxrpc_UDP_error_handler()
rxrpc: Kill set but unused variable 'sp' in rxrpc_process_connection()
rxrpc: Kill set but unused variable 'sp' in rxrpc_rotate_tx_window()
pkt_sched: Kill set but unused variable 'protocol' in tc_classify()
isdn: capi: Use pr_debug() instead of ifdefs.
tg3: Update version to 3.119
tg3: Apply rx_discards fix to 5719/5720
...
Fix up trivial conflicts in arch/x86/Kconfig and net/mac80211/agg-tx.c
as per Davem.
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r-- | net/bluetooth/hci_conn.c | 95 |
1 files changed, 85 insertions, 10 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index 7a6f56b2f49d..3163330cd4f1 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,36 +553,93 @@ 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); +/* Check secure link requirement */ +int hci_conn_check_secure(struct hci_conn *conn, __u8 sec_level) +{ + BT_DBG("conn %p", conn); + + if (sec_level != BT_SECURITY_HIGH) + return 1; /* Accept if non-secure is required */ + + if (conn->key_type == HCI_LK_AUTH_COMBINATION || + (conn->key_type == HCI_LK_COMBINATION && + conn->pin_length == 16)) + return 1; + + return 0; /* Reject not secure link */ +} +EXPORT_SYMBOL(hci_conn_check_secure); + /* Change link key */ int hci_conn_change_link_key(struct hci_conn *conn) { |