Commit 9719f8af authored by Marcel Holtmann's avatar Marcel Holtmann

[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: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 77db1980
...@@ -474,7 +474,7 @@ struct hci_proto { ...@@ -474,7 +474,7 @@ struct hci_proto {
int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags); 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 (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
int (*auth_cfm) (struct hci_conn *conn, __u8 status); 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) 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) ...@@ -532,17 +532,17 @@ static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
hp->auth_cfm(conn, 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; register struct hci_proto *hp;
hp = hci_proto[HCI_PROTO_L2CAP]; hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->encrypt_cfm) if (hp && hp->encrypt_cfm)
hp->encrypt_cfm(conn, status); hp->encrypt_cfm(conn, status, encrypt);
hp = hci_proto[HCI_PROTO_SCO]; hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->encrypt_cfm) if (hp && hp->encrypt_cfm)
hp->encrypt_cfm(conn, status); hp->encrypt_cfm(conn, status, encrypt);
} }
int hci_register_proto(struct hci_proto *hproto); 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 ...@@ -579,7 +579,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
{ {
struct list_head *p; struct list_head *p;
hci_proto_encrypt_cfm(conn, status); hci_proto_encrypt_cfm(conn, status, encrypt);
read_lock_bh(&hci_cb_list_lock); read_lock_bh(&hci_cb_list_lock);
list_for_each(p, &hci_cb_list) { list_for_each(p, &hci_cb_list) {
......
...@@ -2197,7 +2197,7 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) ...@@ -2197,7 +2197,7 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
return 0; 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_chan_list *l;
struct l2cap_conn *conn = hcon->l2cap_data; struct l2cap_conn *conn = hcon->l2cap_data;
...@@ -2215,8 +2215,19 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status) ...@@ -2215,8 +2215,19 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status)
read_lock(&l->lock); read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
struct l2cap_pinfo *pi = l2cap_pi(sk);
bh_lock_sock(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) { if (sk->sk_state != BT_CONNECT2) {
bh_unlock_sock(sk); bh_unlock_sock(sk);
continue; continue;
......
...@@ -2003,6 +2003,14 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt) ...@@ -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) { list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list); 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)) if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
continue; continue;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment