Skip to content

Commit

Permalink
Bluetooth: Replace RFCOMM link mode with security level
Browse files Browse the repository at this point in the history
Change the RFCOMM internals to use the new security levels and remove
the link mode details.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
  • Loading branch information
Marcel Holtmann committed Feb 27, 2009
1 parent 2af6b9d commit 9f2c8a0
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 31 deletions.
7 changes: 4 additions & 3 deletions include/net/bluetooth/rfcomm.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ struct rfcomm_dlc {
u8 remote_v24_sig;
u8 mscex;
u8 out;

u32 link_mode;
u8 sec_level;
u8 role_switch;
u32 defer_setup;

uint mtu;
Expand Down Expand Up @@ -307,7 +307,8 @@ struct rfcomm_pinfo {
struct bt_sock bt;
struct rfcomm_dlc *dlc;
u8 channel;
u32 link_mode;
u8 sec_level;
u8 role_switch;
};

int rfcomm_init_sockets(void);
Expand Down
28 changes: 7 additions & 21 deletions net/bluetooth/rfcomm/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,21 +223,11 @@ static int rfcomm_l2sock_create(struct socket **sock)
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 l2cap_conn *conn = l2cap_pi(sk)->conn;

if (d->link_mode & RFCOMM_LM_SECURE)
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;
return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level);
}

/* ---- RFCOMM DLCs ---- */
Expand Down Expand Up @@ -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;

if (s->state == BT_CONNECTED) {
if (rfcomm_check_link_mode(d))
if (rfcomm_check_security(d))
rfcomm_send_pn(s, 1, d);
else
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
Expand Down Expand Up @@ -1192,15 +1182,15 @@ void rfcomm_dlc_accept(struct rfcomm_dlc *d)
d->state_change(d, 0);
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);

rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
}

static void rfcomm_check_accept(struct rfcomm_dlc *d)
{
if (rfcomm_check_link_mode(d)) {
if (rfcomm_check_security(d)) {
if (d->defer_setup) {
set_bit(RFCOMM_DEFER_SETUP, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
Expand Down Expand Up @@ -1660,7 +1650,7 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
d = list_entry(p, struct rfcomm_dlc, list);
if (d->state == BT_CONFIG) {
d->mtu = s->mtu;
if (rfcomm_check_link_mode(d)) {
if (rfcomm_check_security(d)) {
rfcomm_send_pn(s, 1, d);
} else {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
Expand Down Expand Up @@ -1748,10 +1738,6 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
} 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);
}
continue;
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
rfcomm_dlc_clear_timer(d);
Expand Down Expand Up @@ -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);

if (!status && encrypt == 0x00 &&
(d->link_mode & RFCOMM_LM_ENCRYPT) &&
d->sec_level == BT_SECURITY_HIGH &&
(d->state == BT_CONNECTED ||
d->state == BT_CONFIG)) {
__rfcomm_dlc_close(d, ECONNREFUSED);
Expand Down
75 changes: 68 additions & 7 deletions net/bluetooth/rfcomm/sock.c
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,19 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)

if (parent) {
sk->sk_type = parent->sk_type;
pi->link_mode = rfcomm_pi(parent)->link_mode;
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 {
pi->link_mode = 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 = {
Expand Down Expand Up @@ -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);
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);
if (!err)
Expand Down Expand Up @@ -741,7 +747,14 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
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;

default:
Expand All @@ -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)
{
struct sock *sk = sock->sk;
int err = 0;
struct bt_security sec;
int len, err = 0;
u32 opt;

BT_DBG("sk %p", sk);
Expand All @@ -767,6 +781,23 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
lock_sock(sk);

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:
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
err = -EINVAL;
Expand Down Expand Up @@ -796,6 +827,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
struct sock *l2cap_sk;
struct rfcomm_conninfo cinfo;
int len, err = 0;
u32 opt;

BT_DBG("sk %p", sk);

Expand All @@ -806,7 +838,26 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u

switch (optname) {
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;
break;

Expand Down Expand Up @@ -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)
{
struct sock *sk = sock->sk;
struct bt_security sec;
int len, err = 0;

BT_DBG("sk %p", sk);
Expand All @@ -853,6 +905,15 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
lock_sock(sk);

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:
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
err = -EINVAL;
Expand Down

0 comments on commit 9f2c8a0

Please sign in to comment.