Recent tests with various Bluetooth headsets have shown that some of
them don't enforce authentication and encryption when connecting. All
of them leave it up to the host stack to enforce it. Non of them should
allow unencrypted connections, but that is how it is. So in case the
link mode settings require authentication and/or encryption it will now
also be enforced on outgoing RFCOMM connections. Previously this was
only done for incoming connections.
This support has a small drawback from a protocol level point of view
since the host stack can't really tell with 100% certainty if a remote
side is already authenticated or not. So if both sides are configured
to enforce authentication it will be requested twice. Most Bluetooth
chips are caching this information and thus no extra authentication
procedure has to be triggered over-the-air, but it can happen.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
u8 priority;
u8 v24_sig;
u8 mscex;
u8 priority;
u8 v24_sig;
u8 mscex;
#define BT_DBG(D...)
#endif
#define BT_DBG(D...)
#endif
static int disable_cfc = 0;
static int channel_mtu = -1;
static int disable_cfc = 0;
static int channel_mtu = -1;
+static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
+{
+ struct sock *sk = d->session->sock->sk;
+
+ if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
+ if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
+ return 1;
+ } else if (d->link_mode & RFCOMM_LM_AUTH) {
+ if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
+ return 1;
+ }
+
+ return 0;
+}
+
/* ---- RFCOMM DLCs ---- */
static void rfcomm_dlc_timeout(unsigned long arg)
{
/* ---- RFCOMM DLCs ---- */
static void rfcomm_dlc_timeout(unsigned long arg)
{
d->addr = __addr(s->initiator, dlci);
d->priority = 7;
d->addr = __addr(s->initiator, dlci);
d->priority = 7;
d->mtu = s->mtu;
d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
d->mtu = s->mtu;
d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
- if (s->state == BT_CONNECTED)
- rfcomm_send_pn(s, 1, d);
+ if (s->state == BT_CONNECTED) {
+ if (rfcomm_check_link_mode(d))
+ set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+ else
+ rfcomm_send_pn(s, 1, d);
+ }
+
rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
-static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
-{
- struct sock *sk = d->session->sock->sk;
-
- if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
- if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
- return 1;
- } else if (d->link_mode & RFCOMM_LM_AUTH) {
- if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
- return 1;
- }
-
- return 0;
-}
-
static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
- return 0;
- }
-
- rfcomm_dlc_accept(d);
+ } else
+ rfcomm_dlc_accept(d);
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
- return 0;
- }
-
- rfcomm_dlc_accept(d);
+ } else
+ rfcomm_dlc_accept(d);
} else {
rfcomm_send_dm(s, dlci);
}
} else {
rfcomm_send_dm(s, dlci);
}
d = list_entry(p, struct rfcomm_dlc, list);
if (d->state == BT_CONFIG) {
d->mtu = s->mtu;
d = list_entry(p, struct rfcomm_dlc, list);
if (d->state == BT_CONFIG) {
d->mtu = s->mtu;
- rfcomm_send_pn(s, 1, d);
+ if (rfcomm_check_link_mode(d)) {
+ set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+ rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+ } else
+ rfcomm_send_pn(s, 1, d);
if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) {
rfcomm_dlc_clear_timer(d);
if (test_and_clear_bit(RFCOMM_AUTH_ACCEPT, &d->flags)) {
rfcomm_dlc_clear_timer(d);
+ if (d->out) {
+ rfcomm_send_pn(s, 1, d);
+ rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
+ } else
+ rfcomm_dlc_accept(d);
if (d->link_mode & RFCOMM_LM_SECURE) {
struct sock *sk = s->sock->sk;
hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
if (d->link_mode & RFCOMM_LM_SECURE) {
struct sock *sk = s->sock->sk;
hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
continue;
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
rfcomm_dlc_clear_timer(d);
continue;
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
rfcomm_dlc_clear_timer(d);
- rfcomm_send_dm(s, d->dlci);
+ if (!d->out)
+ rfcomm_send_dm(s, d->dlci);
+ else
+ d->state = BT_CLOSED;
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
continue;
if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
continue;
if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
- d->mscex == RFCOMM_MSCEX_OK)
+ d->mscex == RFCOMM_MSCEX_OK)
rfcomm_process_tx(d);
}
}
rfcomm_process_tx(d);
}
}
sk->sk_destruct = rfcomm_sock_destruct;
sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;
sk->sk_destruct = rfcomm_sock_destruct;
sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT;
- sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
- sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+ sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
+ sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10;
sock_reset_flag(sk, SOCK_ZAPPED);
sk->sk_protocol = proto;
sock_reset_flag(sk, SOCK_ZAPPED);
sk->sk_protocol = proto;
- sk->sk_state = BT_OPEN;
+ sk->sk_state = BT_OPEN;
bt_sock_link(&rfcomm_sk_list, sk);
bt_sock_link(&rfcomm_sk_list, sk);
bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
rfcomm_pi(sk)->channel = sa->rc_channel;
bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
rfcomm_pi(sk)->channel = sa->rc_channel;
+ d->link_mode = rfcomm_pi(sk)->link_mode;
+
err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
if (!err)
err = bt_sock_wait_state(sk, BT_CONNECTED,
err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
if (!err)
err = bt_sock_wait_state(sk, BT_CONNECTED,