[Bluetooth] Disconnect when encryption gets disabled

The Bluetooth specification allows to enable or disable the encryption
of an ACL link at any time by either the peer or the remote device. If
a L2CAP or RFCOMM connection requested an encrypted link, they will now
disconnect that link if the encryption gets disabled. Higher protocols
that don't care about encryption (like SDP) are not affected.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
Marcel Holtmann 2008-07-14 20:13:45 +02:00
parent 77db198056
commit 9719f8afce
3 changed files with 25 additions and 6 deletions

View File

@ -474,7 +474,7 @@ struct hci_proto {
int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
int (*auth_cfm) (struct hci_conn *conn, __u8 status);
int (*encrypt_cfm) (struct hci_conn *conn, __u8 status);
int (*encrypt_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
};
static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
@ -532,17 +532,17 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
hp->auth_cfm(conn, status);
}
static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status)
static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt)
{
register struct hci_proto *hp;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->encrypt_cfm)
hp->encrypt_cfm(conn, status);
hp->encrypt_cfm(conn, status, encrypt);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->encrypt_cfm)
hp->encrypt_cfm(conn, status);
hp->encrypt_cfm(conn, status, encrypt);
}
int hci_register_proto(struct hci_proto *hproto);
@ -579,7 +579,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
{
struct list_head *p;
hci_proto_encrypt_cfm(conn, status);
hci_proto_encrypt_cfm(conn, status, encrypt);
read_lock_bh(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) {

View File

@ -2197,7 +2197,7 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
return 0;
}
static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
{
struct l2cap_chan_list *l;
struct l2cap_conn *conn = hcon->l2cap_data;
@ -2215,8 +2215,19 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
struct l2cap_pinfo *pi = l2cap_pi(sk);
bh_lock_sock(sk);
if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
(sk->sk_state == BT_CONNECTED ||
sk->sk_state == BT_CONFIG) &&
!status && encrypt == 0x00) {
__l2cap_sock_close(sk, ECONNREFUSED);
bh_unlock_sock(sk);
continue;
}
if (sk->sk_state != BT_CONNECT2) {
bh_unlock_sock(sk);
continue;

View File

@ -2003,6 +2003,14 @@ static void rfcomm_encrypt_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 ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
(d->state == BT_CONNECTED ||
d->state == BT_CONFIG) &&
!status && encrypt == 0x00) {
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
continue;