>From d72c9195905214020408d989eca902330d3c19f0 Mon Sep 17 00:00:00 2001 From: Ville Tervo Date: Mon, 29 Dec 2008 13:56:30 +0200 Subject: [PATCH 4/7] bluetooth: l2cap seclevel This patch introduces preliminary l2cap seclevel support. --- net/bluetooth/l2cap.c | 130 +++++++++++++++++++++++++++++++++++++------------ 1 files changed, 98 insertions(+), 32 deletions(-) diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 9610a9c..6a643f7 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -83,6 +83,9 @@ static void l2cap_sock_timeout(unsigned long arg) bh_lock_sock(sk); if (sk->sk_state == BT_CONNECT && + (l2cap_pi(sk)->seclevel == BT_SECURITY_HIGH)) + reason = ECONNREFUSED; + else if (sk->sk_state == BT_CONNECT && (l2cap_pi(sk)->link_mode & (L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE))) reason = ECONNREFUSED; @@ -268,10 +271,16 @@ static inline int l2cap_check_link_mode(struct sock *sk) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; + if (l2cap_pi(sk)->seclevel == BT_SECURITY_MEDIUM) + return hci_conn_encrypt(conn->hcon); + if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) || (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)) return hci_conn_encrypt(conn->hcon); + if (l2cap_pi(sk)->seclevel == BT_SECURITY_HIGH) + return hci_conn_auth(conn->hcon); + if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH) return hci_conn_auth(conn->hcon); @@ -790,18 +799,32 @@ static int l2cap_do_connect(struct sock *sk) err = -ENOMEM; - if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH || - l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT || + auth_type = 0; + switch (l2cap_pi(sk)->seclevel) { + case BT_SECURITY_HIGH: + auth_type = HCI_AT_GENERAL_BONDING_MITM; + break; + case BT_SECURITY_MEDIUM: + case BT_SECURITY_LOW: + auth_type = HCI_AT_GENERAL_BONDING; + break; + case BT_SECURITY_SDP: + auth_type = HCI_AT_NO_BONDING; + break; + default: + if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH || + l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT || l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) { - if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) - auth_type = HCI_AT_NO_BONDING_MITM; - else - auth_type = HCI_AT_GENERAL_BONDING_MITM; - } else { - if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) - auth_type = HCI_AT_NO_BONDING; - else - auth_type = HCI_AT_GENERAL_BONDING; + if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) + auth_type = HCI_AT_NO_BONDING_MITM; + else + auth_type = HCI_AT_GENERAL_BONDING_MITM; + } else { + if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) + auth_type = HCI_AT_NO_BONDING; + else + auth_type = HCI_AT_GENERAL_BONDING; + } } hcon = hci_connect(hdev, ACL_LINK, dst, auth_type); @@ -1115,6 +1138,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch { struct sock *sk = sock->sk; struct l2cap_options opts; + struct bt_security sec; int err = 0, len; u32 opt; @@ -1122,36 +1146,61 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch lock_sock(sk); - switch (optname) { - case L2CAP_OPTIONS: - opts.imtu = l2cap_pi(sk)->imtu; - opts.omtu = l2cap_pi(sk)->omtu; - opts.flush_to = l2cap_pi(sk)->flush_to; - opts.mode = L2CAP_MODE_BASIC; + if (level== SOL_BLUETOOTH) { + 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; + } - len = min_t(unsigned int, sizeof(opts), optlen); - if (copy_from_user((char *) &opts, optval, len)) { - err = -EFAULT; + if (sec.level > BT_SECURITY_HIGH) { + err = -EINVAL; + break; + } + + l2cap_pi(sk)->seclevel = sec.level; break; } - l2cap_pi(sk)->imtu = opts.imtu; - l2cap_pi(sk)->omtu = opts.omtu; - break; + default: + err = -ENOPROTOOPT; + break; + } else if (level = SOL_L2CAP) { + switch (optname) { + case L2CAP_OPTIONS: + opts.imtu = l2cap_pi(sk)->imtu; + opts.omtu = l2cap_pi(sk)->omtu; + opts.flush_to = l2cap_pi(sk)->flush_to; + opts.mode = L2CAP_MODE_BASIC; + + len = min_t(unsigned int, sizeof(opts), optlen); + if (copy_from_user((char *) &opts, optval, len)) { + err = -EFAULT; + break; + } - case L2CAP_LM: - if (get_user(opt, (u32 __user *) optval)) { - err = -EFAULT; + l2cap_pi(sk)->imtu = opts.imtu; + l2cap_pi(sk)->omtu = opts.omtu; break; - } - l2cap_pi(sk)->link_mode = opt; - break; + case L2CAP_LM: + if (get_user(opt, (u32 __user *) optval)) { + err = -EFAULT; + break; + } - default: + l2cap_pi(sk)->link_mode = opt; + break; + + default: + err = -ENOPROTOOPT; + break; + } + } else err = -ENOPROTOOPT; - break; - } release_sock(sk); return err; @@ -2209,6 +2258,13 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status) bh_lock_sock(sk); + if (pi->seclevel == BT_SECURITY_HIGH && + !(hcon->link_mode & HCI_LM_ENCRYPT) && + !status) { + bh_unlock_sock(sk); + continue; + } + if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) && !(hcon->link_mode & HCI_LM_ENCRYPT) && !status) { @@ -2279,6 +2335,16 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt) bh_lock_sock(sk); + if ((pi->seclevel == BT_SECURITY_HIGH || pi->seclevel == BT_SECURITY_MEDIUM || + pi->seclevel == BT_SECURITY_LOW) && + (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) && + !status && encrypt == 0x00) { + __l2cap_sock_close(sk, ECONNREFUSED); + bh_unlock_sock(sk); + continue; + } + + if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) && (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG) && -- 1.6.0.4