Loading include/net/bluetooth/rfcomm.h +4 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading net/bluetooth/rfcomm/core.c +7 −21 Original line number Diff line number Diff line Loading @@ -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 ---- */ Loading Loading @@ -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); Loading Loading @@ -1192,7 +1182,7 @@ 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); Loading @@ -1200,7 +1190,7 @@ void rfcomm_dlc_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) { set_bit(RFCOMM_DEFER_SETUP, &d->flags); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading net/bluetooth/rfcomm/sock.c +68 −7 Original line number Diff line number Diff line Loading @@ -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 = { Loading Loading @@ -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) Loading Loading @@ -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: Loading @@ -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); Loading @@ -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; Loading Loading @@ -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); Loading @@ -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; Loading Loading @@ -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); Loading @@ -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; Loading Loading
include/net/bluetooth/rfcomm.h +4 −3 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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); Loading
net/bluetooth/rfcomm/core.c +7 −21 Original line number Diff line number Diff line Loading @@ -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 ---- */ Loading Loading @@ -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); Loading Loading @@ -1192,7 +1182,7 @@ 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); Loading @@ -1200,7 +1190,7 @@ void rfcomm_dlc_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) { set_bit(RFCOMM_DEFER_SETUP, &d->flags); rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT); Loading Loading @@ -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); Loading Loading @@ -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); Loading Loading @@ -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); Loading
net/bluetooth/rfcomm/sock.c +68 −7 Original line number Diff line number Diff line Loading @@ -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 = { Loading Loading @@ -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) Loading Loading @@ -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: Loading @@ -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); Loading @@ -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; Loading Loading @@ -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); Loading @@ -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; Loading Loading @@ -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); Loading @@ -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; Loading