summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2009-01-16 08:17:51 +0100
committerNick Pelly <npelly@google.com>2009-04-06 17:39:27 -0700
commit7d0a42ff97c88e4e113d153fbf4345ac58142f80 (patch)
treea412c96209c9efdf66b82a257fa4f4852da97aa1 /net
parentd2ad5456d3e2092be2908ee099fa34859540b6f4 (diff)
Bluetooth: Pause RFCOMM TX when encryption drops
A role switch with devices following the Bluetooth pre-2.1 standards or without Encryption Pause and Resume support is not possible if encryption is enabled. Most newer headsets require the role switch, but also require that the connection is encrypted. For connections with a high security mode setting, the link will be immediately dropped. When the connection uses medium security mode setting, then a grace period is introduced where the TX is halted and the remote device gets a change to re-enable encryption after the role switch. If not re-enabled the link will be dropped. Based on initial work by Ville Tervo <ville.tervo@nokia.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/rfcomm/core.c23
1 files changed, 17 insertions, 6 deletions
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index db83f92d274c..dafaee91cdfb 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1979,12 +1979,23 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
- if (!status && encrypt == 0x00 &&
- d->sec_level == BT_SECURITY_HIGH &&
- (d->state == BT_CONNECTED ||
- d->state == BT_CONFIG)) {
- __rfcomm_dlc_close(d, ECONNREFUSED);
- continue;
+ if (test_and_clear_bit(RFCOMM_SEC_PENDING, &d->flags)) {
+ rfcomm_dlc_clear_timer(d);
+ if (status || encrypt == 0x00) {
+ __rfcomm_dlc_close(d, ECONNREFUSED);
+ continue;
+ }
+ }
+
+ if (d->state == BT_CONNECTED && !status && encrypt == 0x00) {
+ if (d->sec_level == BT_SECURITY_MEDIUM) {
+ set_bit(RFCOMM_SEC_PENDING, &d->flags);
+ rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+ continue;
+ } else if (d->sec_level == BT_SECURITY_HIGH) {
+ __rfcomm_dlc_close(d, ECONNREFUSED);
+ continue;
+ }
}
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))