BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
+ conn->disc_reason = 0x13;
+
l2cap_pi(sk)->conn = conn;
if (sk->sk_type == SOCK_SEQPACKET) {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
__u8 auth_type;
- switch (l2cap_pi(sk)->sec_level) {
- case BT_SECURITY_HIGH:
- auth_type = HCI_AT_GENERAL_BONDING_MITM;
- break;
- case BT_SECURITY_MEDIUM:
- auth_type = HCI_AT_GENERAL_BONDING;
- break;
- default:
- auth_type = HCI_AT_NO_BONDING;
- break;
+ if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
+ if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+ auth_type = HCI_AT_NO_BONDING_MITM;
+ else
+ auth_type = HCI_AT_NO_BONDING;
+
+ if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
+ l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+ } else {
+ switch (l2cap_pi(sk)->sec_level) {
+ case BT_SECURITY_HIGH:
+ auth_type = HCI_AT_GENERAL_BONDING_MITM;
+ break;
+ case BT_SECURITY_MEDIUM:
+ auth_type = HCI_AT_GENERAL_BONDING;
+ break;
+ default:
+ auth_type = HCI_AT_NO_BONDING;
+ break;
+ }
}
return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
spin_lock_init(&conn->lock);
rwlock_init(&conn->chan_list.lock);
+ conn->disc_reason = 0x13;
+
return conn;
}
len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len);
+ if (la.l2_cid)
+ return -EINVAL;
+
lock_sock(sk);
if (sk->sk_state != BT_OPEN) {
struct sockaddr_l2 la;
int len, err = 0;
- lock_sock(sk);
-
BT_DBG("sk %p", sk);
- if (!addr || addr->sa_family != AF_BLUETOOTH) {
- err = -EINVAL;
- goto done;
- }
+ if (!addr || addr->sa_family != AF_BLUETOOTH)
+ return -EINVAL;
memset(&la, 0, sizeof(la));
len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len);
+ if (la.l2_cid)
+ return -EINVAL;
+
+ lock_sock(sk);
+
if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) {
err = -EINVAL;
goto done;
/* Check if the ACL is secure enough (if not SDP) */
if (psm != cpu_to_le16(0x0001) &&
!hci_conn_check_link_mode(conn->hcon)) {
+ conn->disc_reason = 0x05;
result = L2CAP_CR_SEC_BLOCK;
goto response;
}
return 0;
}
-static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
+static int l2cap_disconn_ind(struct hci_conn *hcon)
+{
+ struct l2cap_conn *conn = hcon->l2cap_data;
+
+ BT_DBG("hcon %p", hcon);
+
+ if (hcon->type != ACL_LINK || !conn)
+ return 0x13;
+
+ return conn->disc_reason;
+}
+
+static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
.connect_ind = l2cap_connect_ind,
.connect_cfm = l2cap_connect_cfm,
.disconn_ind = l2cap_disconn_ind,
+ .disconn_cfm = l2cap_disconn_cfm,
.security_cfm = l2cap_security_cfm,
.recv_acldata = l2cap_recv_acldata
};