mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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
					
				
					 3 changed files with 79 additions and 31 deletions
				
			
		| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 ---- */
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 = {
 | 
			
		||||
| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			@ -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:
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -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…
	
		Reference in a new issue