int (*connect_ind) (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
int (*connect_cfm) (struct hci_conn *conn, __u8 status);
- int (*disconn_ind) (struct hci_conn *conn, __u8 reason);
+ int (*disconn_ind) (struct hci_conn *conn);
+ int (*disconn_cfm) (struct hci_conn *conn, __u8 reason);
int (*recv_acldata) (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
int (*recv_scodata) (struct hci_conn *conn, struct sk_buff *skb);
int (*security_cfm) (struct hci_conn *conn, __u8 status, __u8 encrypt);
hp->connect_cfm(conn, status);
}
-static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
+static inline int hci_proto_disconn_ind(struct hci_conn *conn)
{
register struct hci_proto *hp;
+ int reason = 0x13;
hp = hci_proto[HCI_PROTO_L2CAP];
if (hp && hp->disconn_ind)
- hp->disconn_ind(conn, reason);
+ reason = hp->disconn_ind(conn);
hp = hci_proto[HCI_PROTO_SCO];
if (hp && hp->disconn_ind)
- hp->disconn_ind(conn, reason);
+ reason = hp->disconn_ind(conn);
+
+ return reason;
+}
+
+static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
+{
+ register struct hci_proto *hp;
+
+ hp = hci_proto[HCI_PROTO_L2CAP];
+ if (hp && hp->disconn_cfm)
+ hp->disconn_cfm(conn, reason);
+
+ hp = hci_proto[HCI_PROTO_SCO];
+ if (hp && hp->disconn_cfm)
+ hp->disconn_cfm(conn, reason);
}
static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
__u8 rx_ident;
__u8 tx_ident;
+ __u8 disc_reason;
+
struct l2cap_chan_list chan_list;
};
{
struct hci_conn *conn = (void *) arg;
struct hci_dev *hdev = conn->hdev;
+ __u8 reason;
BT_DBG("conn %p state %d", conn, conn->state);
break;
case BT_CONFIG:
case BT_CONNECTED:
- hci_acl_disconn(conn, 0x13);
+ reason = hci_proto_disconn_ind(conn);
+ hci_acl_disconn(conn, reason);
break;
default:
conn->state = BT_CLOSED;
hci_conn_del_sysfs(c);
- hci_proto_disconn_ind(c, 0x16);
+ hci_proto_disconn_cfm(c, 0x16);
hci_conn_del(c);
}
}
hci_conn_del_sysfs(conn);
- hci_proto_disconn_ind(conn, ev->reason);
+ hci_proto_disconn_cfm(conn, ev->reason);
hci_conn_del(conn);
}
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) {
spin_lock_init(&conn->lock);
rwlock_init(&conn->chan_list.lock);
+ conn->disc_reason = 0x13;
+
return conn;
}
/* 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
};
return 0;
}
-static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
+static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
.id = HCI_PROTO_SCO,
.connect_ind = sco_connect_ind,
.connect_cfm = sco_connect_cfm,
- .disconn_ind = sco_disconn_ind,
+ .disconn_cfm = sco_disconn_cfm,
.recv_scodata = sco_recv_scodata
};