Bluetooth: Replace RFCOMM link mode with security level
Change the RFCOMM internals to use the new security levels and remove the link mode details. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
2af6b9d518
commit
9f2c8a03fb
|
@ -183,8 +183,8 @@ struct rfcomm_dlc {
|
||||||
u8 remote_v24_sig;
|
u8 remote_v24_sig;
|
||||||
u8 mscex;
|
u8 mscex;
|
||||||
u8 out;
|
u8 out;
|
||||||
|
u8 sec_level;
|
||||||
u32 link_mode;
|
u8 role_switch;
|
||||||
u32 defer_setup;
|
u32 defer_setup;
|
||||||
|
|
||||||
uint mtu;
|
uint mtu;
|
||||||
|
@ -307,7 +307,8 @@ struct rfcomm_pinfo {
|
||||||
struct bt_sock bt;
|
struct bt_sock bt;
|
||||||
struct rfcomm_dlc *dlc;
|
struct rfcomm_dlc *dlc;
|
||||||
u8 channel;
|
u8 channel;
|
||||||
u32 link_mode;
|
u8 sec_level;
|
||||||
|
u8 role_switch;
|
||||||
};
|
};
|
||||||
|
|
||||||
int rfcomm_init_sockets(void);
|
int rfcomm_init_sockets(void);
|
||||||
|
|
|
@ -223,21 +223,11 @@ static int rfcomm_l2sock_create(struct socket **sock)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
|
static inline int rfcomm_check_security(struct rfcomm_dlc *d)
|
||||||
{
|
{
|
||||||
struct sock *sk = d->session->sock->sk;
|
struct sock *sk = d->session->sock->sk;
|
||||||
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
|
||||||
|
|
||||||
if (d->link_mode & RFCOMM_LM_SECURE)
|
return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level);
|
||||||
return hci_conn_security(conn->hcon, BT_SECURITY_HIGH);
|
|
||||||
|
|
||||||
if (d->link_mode & RFCOMM_LM_ENCRYPT)
|
|
||||||
return hci_conn_security(conn->hcon, BT_SECURITY_MEDIUM);
|
|
||||||
|
|
||||||
if (d->link_mode & RFCOMM_LM_AUTH)
|
|
||||||
return hci_conn_security(conn->hcon, BT_SECURITY_LOW);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---- RFCOMM DLCs ---- */
|
/* ---- RFCOMM DLCs ---- */
|
||||||
|
@ -390,7 +380,7 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
|
||||||
d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
|
d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
|
||||||
|
|
||||||
if (s->state == BT_CONNECTED) {
|
if (s->state == BT_CONNECTED) {
|
||||||
if (rfcomm_check_link_mode(d))
|
if (rfcomm_check_security(d))
|
||||||
rfcomm_send_pn(s, 1, d);
|
rfcomm_send_pn(s, 1, d);
|
||||||
else
|
else
|
||||||
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
|
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
|
||||||
|
@ -1192,7 +1182,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d)
|
||||||
d->state_change(d, 0);
|
d->state_change(d, 0);
|
||||||
rfcomm_dlc_unlock(d);
|
rfcomm_dlc_unlock(d);
|
||||||
|
|
||||||
if (d->link_mode & RFCOMM_LM_MASTER)
|
if (d->role_switch)
|
||||||
hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
|
hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
|
||||||
|
|
||||||
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
|
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
|
||||||
|
@ -1200,7 +1190,7 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d)
|
||||||
|
|
||||||
static void rfcomm_check_accept(struct rfcomm_dlc *d)
|
static void rfcomm_check_accept(struct rfcomm_dlc *d)
|
||||||
{
|
{
|
||||||
if (rfcomm_check_link_mode(d)) {
|
if (rfcomm_check_security(d)) {
|
||||||
if (d->defer_setup) {
|
if (d->defer_setup) {
|
||||||
set_bit(RFCOMM_DEFER_SETUP, &d->flags);
|
set_bit(RFCOMM_DEFER_SETUP, &d->flags);
|
||||||
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
|
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
|
||||||
|
@ -1660,7 +1650,7 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
|
||||||
d = list_entry(p, struct rfcomm_dlc, list);
|
d = list_entry(p, struct rfcomm_dlc, list);
|
||||||
if (d->state == BT_CONFIG) {
|
if (d->state == BT_CONFIG) {
|
||||||
d->mtu = s->mtu;
|
d->mtu = s->mtu;
|
||||||
if (rfcomm_check_link_mode(d)) {
|
if (rfcomm_check_security(d)) {
|
||||||
rfcomm_send_pn(s, 1, d);
|
rfcomm_send_pn(s, 1, d);
|
||||||
} else {
|
} else {
|
||||||
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
|
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
|
||||||
|
@ -1748,10 +1738,6 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
|
||||||
} else
|
} else
|
||||||
rfcomm_dlc_accept(d);
|
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);
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
|
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
|
||||||
rfcomm_dlc_clear_timer(d);
|
rfcomm_dlc_clear_timer(d);
|
||||||
|
@ -1994,7 +1980,7 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
|
||||||
d = list_entry(p, struct rfcomm_dlc, list);
|
d = list_entry(p, struct rfcomm_dlc, list);
|
||||||
|
|
||||||
if (!status && encrypt == 0x00 &&
|
if (!status && encrypt == 0x00 &&
|
||||||
(d->link_mode & RFCOMM_LM_ENCRYPT) &&
|
d->sec_level == BT_SECURITY_HIGH &&
|
||||||
(d->state == BT_CONNECTED ||
|
(d->state == BT_CONNECTED ||
|
||||||
d->state == BT_CONFIG)) {
|
d->state == BT_CONFIG)) {
|
||||||
__rfcomm_dlc_close(d, ECONNREFUSED);
|
__rfcomm_dlc_close(d, ECONNREFUSED);
|
||||||
|
|
|
@ -261,14 +261,19 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
sk->sk_type = parent->sk_type;
|
sk->sk_type = parent->sk_type;
|
||||||
pi->link_mode = rfcomm_pi(parent)->link_mode;
|
|
||||||
pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
|
pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
|
||||||
|
|
||||||
|
pi->sec_level = rfcomm_pi(parent)->sec_level;
|
||||||
|
pi->role_switch = rfcomm_pi(parent)->role_switch;
|
||||||
} else {
|
} else {
|
||||||
pi->link_mode = 0;
|
|
||||||
pi->dlc->defer_setup = 0;
|
pi->dlc->defer_setup = 0;
|
||||||
|
|
||||||
|
pi->sec_level = BT_SECURITY_LOW;
|
||||||
|
pi->role_switch = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pi->dlc->link_mode = pi->link_mode;
|
pi->dlc->sec_level = pi->sec_level;
|
||||||
|
pi->dlc->role_switch = pi->role_switch;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct proto rfcomm_proto = {
|
static struct proto rfcomm_proto = {
|
||||||
|
@ -408,7 +413,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
|
||||||
bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
|
bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
|
||||||
rfcomm_pi(sk)->channel = sa->rc_channel;
|
rfcomm_pi(sk)->channel = sa->rc_channel;
|
||||||
|
|
||||||
d->link_mode = rfcomm_pi(sk)->link_mode;
|
d->sec_level = rfcomm_pi(sk)->sec_level;
|
||||||
|
d->role_switch = rfcomm_pi(sk)->role_switch;
|
||||||
|
|
||||||
err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
|
err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
|
||||||
if (!err)
|
if (!err)
|
||||||
|
@ -741,7 +747,14 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
rfcomm_pi(sk)->link_mode = opt;
|
if (opt & RFCOMM_LM_AUTH)
|
||||||
|
rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
|
||||||
|
if (opt & RFCOMM_LM_ENCRYPT)
|
||||||
|
rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
|
||||||
|
if (opt & RFCOMM_LM_SECURE)
|
||||||
|
rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;
|
||||||
|
|
||||||
|
rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -756,7 +769,8 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
|
||||||
static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
|
static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
|
||||||
{
|
{
|
||||||
struct sock *sk = sock->sk;
|
struct sock *sk = sock->sk;
|
||||||
int err = 0;
|
struct bt_security sec;
|
||||||
|
int len, err = 0;
|
||||||
u32 opt;
|
u32 opt;
|
||||||
|
|
||||||
BT_DBG("sk %p", sk);
|
BT_DBG("sk %p", sk);
|
||||||
|
@ -767,6 +781,23 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
|
|
||||||
switch (optname) {
|
switch (optname) {
|
||||||
|
case BT_SECURITY:
|
||||||
|
sec.level = BT_SECURITY_LOW;
|
||||||
|
|
||||||
|
len = min_t(unsigned int, sizeof(sec), optlen);
|
||||||
|
if (copy_from_user((char *) &sec, optval, len)) {
|
||||||
|
err = -EFAULT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sec.level > BT_SECURITY_HIGH) {
|
||||||
|
err = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
rfcomm_pi(sk)->sec_level = sec.level;
|
||||||
|
break;
|
||||||
|
|
||||||
case BT_DEFER_SETUP:
|
case BT_DEFER_SETUP:
|
||||||
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
|
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
@ -796,6 +827,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
|
||||||
struct sock *l2cap_sk;
|
struct sock *l2cap_sk;
|
||||||
struct rfcomm_conninfo cinfo;
|
struct rfcomm_conninfo cinfo;
|
||||||
int len, err = 0;
|
int len, err = 0;
|
||||||
|
u32 opt;
|
||||||
|
|
||||||
BT_DBG("sk %p", sk);
|
BT_DBG("sk %p", sk);
|
||||||
|
|
||||||
|
@ -806,7 +838,26 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
|
||||||
|
|
||||||
switch (optname) {
|
switch (optname) {
|
||||||
case RFCOMM_LM:
|
case RFCOMM_LM:
|
||||||
if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
|
switch (rfcomm_pi(sk)->sec_level) {
|
||||||
|
case BT_SECURITY_LOW:
|
||||||
|
opt = RFCOMM_LM_AUTH;
|
||||||
|
break;
|
||||||
|
case BT_SECURITY_MEDIUM:
|
||||||
|
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
|
||||||
|
break;
|
||||||
|
case BT_SECURITY_HIGH:
|
||||||
|
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
|
||||||
|
RFCOMM_LM_SECURE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
opt = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rfcomm_pi(sk)->role_switch)
|
||||||
|
opt |= RFCOMM_LM_MASTER;
|
||||||
|
|
||||||
|
if (put_user(opt, (u32 __user *) optval))
|
||||||
err = -EFAULT;
|
err = -EFAULT;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -840,6 +891,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
|
||||||
static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
|
static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
|
||||||
{
|
{
|
||||||
struct sock *sk = sock->sk;
|
struct sock *sk = sock->sk;
|
||||||
|
struct bt_security sec;
|
||||||
int len, err = 0;
|
int len, err = 0;
|
||||||
|
|
||||||
BT_DBG("sk %p", sk);
|
BT_DBG("sk %p", sk);
|
||||||
|
@ -853,6 +905,15 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
|
||||||
lock_sock(sk);
|
lock_sock(sk);
|
||||||
|
|
||||||
switch (optname) {
|
switch (optname) {
|
||||||
|
case BT_SECURITY:
|
||||||
|
sec.level = rfcomm_pi(sk)->sec_level;
|
||||||
|
|
||||||
|
len = min_t(unsigned int, len, sizeof(sec));
|
||||||
|
if (copy_to_user(optval, (char *) &sec, len))
|
||||||
|
err = -EFAULT;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
case BT_DEFER_SETUP:
|
case BT_DEFER_SETUP:
|
||||||
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
|
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
|
|
Loading…
Reference in New Issue