|
@@ -76,11 +76,21 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
|
|
|
static void l2cap_sock_timeout(unsigned long arg)
|
|
|
{
|
|
|
struct sock *sk = (struct sock *) arg;
|
|
|
+ int reason;
|
|
|
|
|
|
BT_DBG("sock %p state %d", sk, sk->sk_state);
|
|
|
|
|
|
bh_lock_sock(sk);
|
|
|
- __l2cap_sock_close(sk, ETIMEDOUT);
|
|
|
+
|
|
|
+ if (sk->sk_state == BT_CONNECT &&
|
|
|
+ (l2cap_pi(sk)->link_mode & (L2CAP_LM_AUTH |
|
|
|
+ L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)))
|
|
|
+ reason = ECONNREFUSED;
|
|
|
+ else
|
|
|
+ reason = ETIMEDOUT;
|
|
|
+
|
|
|
+ __l2cap_sock_close(sk, reason);
|
|
|
+
|
|
|
bh_unlock_sock(sk);
|
|
|
|
|
|
l2cap_sock_kill(sk);
|
|
@@ -240,7 +250,7 @@ static void l2cap_chan_del(struct sock *sk, int err)
|
|
|
hci_conn_put(conn->hcon);
|
|
|
}
|
|
|
|
|
|
- sk->sk_state = BT_CLOSED;
|
|
|
+ sk->sk_state = BT_CLOSED;
|
|
|
sock_set_flag(sk, SOCK_ZAPPED);
|
|
|
|
|
|
if (err)
|
|
@@ -307,14 +317,16 @@ static void l2cap_do_start(struct sock *sk)
|
|
|
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
|
|
|
|
|
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
|
|
|
- struct l2cap_conn_req req;
|
|
|
- req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
- req.psm = l2cap_pi(sk)->psm;
|
|
|
+ if (l2cap_check_link_mode(sk)) {
|
|
|
+ struct l2cap_conn_req req;
|
|
|
+ req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
+ req.psm = l2cap_pi(sk)->psm;
|
|
|
|
|
|
- l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
|
|
+ l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
|
|
|
|
|
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
+ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
L2CAP_CONN_REQ, sizeof(req), &req);
|
|
|
+ }
|
|
|
} else {
|
|
|
struct l2cap_info_req req;
|
|
|
req.type = cpu_to_le16(L2CAP_IT_FEAT_MASK);
|
|
@@ -349,14 +361,16 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
|
|
|
}
|
|
|
|
|
|
if (sk->sk_state == BT_CONNECT) {
|
|
|
- struct l2cap_conn_req req;
|
|
|
- req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
- req.psm = l2cap_pi(sk)->psm;
|
|
|
+ if (l2cap_check_link_mode(sk)) {
|
|
|
+ struct l2cap_conn_req req;
|
|
|
+ req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
+ req.psm = l2cap_pi(sk)->psm;
|
|
|
|
|
|
- l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
|
|
+ l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
|
|
|
|
|
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
+ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
L2CAP_CONN_REQ, sizeof(req), &req);
|
|
|
+ }
|
|
|
} else if (sk->sk_state == BT_CONNECT2) {
|
|
|
struct l2cap_conn_rsp rsp;
|
|
|
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
|
|
@@ -455,7 +469,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
|
|
|
|
|
|
conn->feat_mask = 0;
|
|
|
|
|
|
- setup_timer(&conn->info_timer, l2cap_info_timeout, (unsigned long)conn);
|
|
|
+ setup_timer(&conn->info_timer, l2cap_info_timeout,
|
|
|
+ (unsigned long) conn);
|
|
|
|
|
|
spin_lock_init(&conn->lock);
|
|
|
rwlock_init(&conn->chan_list.lock);
|
|
@@ -567,7 +582,7 @@ static void l2cap_sock_cleanup_listen(struct sock *parent)
|
|
|
while ((sk = bt_accept_dequeue(parent, NULL)))
|
|
|
l2cap_sock_close(sk);
|
|
|
|
|
|
- parent->sk_state = BT_CLOSED;
|
|
|
+ parent->sk_state = BT_CLOSED;
|
|
|
sock_set_flag(parent, SOCK_ZAPPED);
|
|
|
}
|
|
|
|
|
@@ -610,9 +625,8 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
|
|
|
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
l2cap_send_cmd(conn, l2cap_get_ident(conn),
|
|
|
L2CAP_DISCONN_REQ, sizeof(req), &req);
|
|
|
- } else {
|
|
|
+ } else
|
|
|
l2cap_chan_del(sk, reason);
|
|
|
- }
|
|
|
break;
|
|
|
|
|
|
case BT_CONNECT:
|
|
@@ -681,9 +695,9 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p
|
|
|
sock_reset_flag(sk, SOCK_ZAPPED);
|
|
|
|
|
|
sk->sk_protocol = proto;
|
|
|
- sk->sk_state = BT_OPEN;
|
|
|
+ sk->sk_state = BT_OPEN;
|
|
|
|
|
|
- setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long)sk);
|
|
|
+ setup_timer(&sk->sk_timer, l2cap_sock_timeout, (unsigned long) sk);
|
|
|
|
|
|
bt_sock_link(&l2cap_sk_list, sk);
|
|
|
return sk;
|
|
@@ -1201,7 +1215,8 @@ static int l2cap_sock_shutdown(struct socket *sock, int how)
|
|
|
__l2cap_sock_close(sk, 0);
|
|
|
|
|
|
if (sock_flag(sk, SOCK_LINGER) && sk->sk_lingertime)
|
|
|
- err = bt_sock_wait_state(sk, BT_CLOSED, sk->sk_lingertime);
|
|
|
+ err = bt_sock_wait_state(sk, BT_CLOSED,
|
|
|
+ sk->sk_lingertime);
|
|
|
}
|
|
|
release_sock(sk);
|
|
|
return err;
|
|
@@ -1245,6 +1260,11 @@ static void l2cap_chan_ready(struct sock *sk)
|
|
|
*/
|
|
|
parent->sk_data_ready(parent, 0);
|
|
|
}
|
|
|
+
|
|
|
+ if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
|
|
|
+ struct l2cap_conn *conn = l2cap_pi(sk)->conn;
|
|
|
+ hci_conn_change_link_key(conn->hcon);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Copy frame to all raw sockets on that connection */
|
|
@@ -1778,7 +1798,7 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hdr
|
|
|
|
|
|
default:
|
|
|
sk->sk_state = BT_DISCONN;
|
|
|
- sk->sk_err = ECONNRESET;
|
|
|
+ sk->sk_err = ECONNRESET;
|
|
|
l2cap_sock_set_timer(sk, HZ * 5);
|
|
|
{
|
|
|
struct l2cap_disconn_req req;
|
|
@@ -2151,9 +2171,7 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
|
|
|
{
|
|
|
struct l2cap_chan_list *l;
|
|
|
struct l2cap_conn *conn = hcon->l2cap_data;
|
|
|
- struct l2cap_conn_rsp rsp;
|
|
|
struct sock *sk;
|
|
|
- int result;
|
|
|
|
|
|
if (!conn)
|
|
|
return 0;
|
|
@@ -2169,37 +2187,53 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
|
|
|
|
|
|
bh_lock_sock(sk);
|
|
|
|
|
|
- if (sk->sk_state != BT_CONNECT2) {
|
|
|
- bh_unlock_sock(sk);
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
|
|
|
- !(hcon->link_mode & HCI_LM_ENCRYPT)) {
|
|
|
+ !(hcon->link_mode & HCI_LM_ENCRYPT) &&
|
|
|
+ !status) {
|
|
|
bh_unlock_sock(sk);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (!status) {
|
|
|
- sk->sk_state = BT_CONFIG;
|
|
|
- result = 0;
|
|
|
- } else {
|
|
|
- sk->sk_state = BT_DISCONN;
|
|
|
- l2cap_sock_set_timer(sk, HZ/10);
|
|
|
- result = L2CAP_CR_SEC_BLOCK;
|
|
|
- }
|
|
|
+ if (sk->sk_state == BT_CONNECT) {
|
|
|
+ if (!status) {
|
|
|
+ struct l2cap_conn_req req;
|
|
|
+ req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
+ req.psm = l2cap_pi(sk)->psm;
|
|
|
+
|
|
|
+ l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
|
|
+
|
|
|
+ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
+ L2CAP_CONN_REQ, sizeof(req), &req);
|
|
|
+ } else {
|
|
|
+ l2cap_sock_clear_timer(sk);
|
|
|
+ l2cap_sock_set_timer(sk, HZ / 10);
|
|
|
+ }
|
|
|
+ } else if (sk->sk_state == BT_CONNECT2) {
|
|
|
+ struct l2cap_conn_rsp rsp;
|
|
|
+ __u16 result;
|
|
|
+
|
|
|
+ if (!status) {
|
|
|
+ sk->sk_state = BT_CONFIG;
|
|
|
+ result = L2CAP_CR_SUCCESS;
|
|
|
+ } else {
|
|
|
+ sk->sk_state = BT_DISCONN;
|
|
|
+ l2cap_sock_set_timer(sk, HZ / 10);
|
|
|
+ result = L2CAP_CR_SEC_BLOCK;
|
|
|
+ }
|
|
|
|
|
|
- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
|
|
|
- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
- rsp.result = cpu_to_le16(result);
|
|
|
- rsp.status = cpu_to_le16(0);
|
|
|
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
- L2CAP_CONN_RSP, sizeof(rsp), &rsp);
|
|
|
+ rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
|
|
|
+ rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
+ rsp.result = cpu_to_le16(result);
|
|
|
+ rsp.status = cpu_to_le16(0);
|
|
|
+ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
+ L2CAP_CONN_RSP, sizeof(rsp), &rsp);
|
|
|
+ }
|
|
|
|
|
|
bh_unlock_sock(sk);
|
|
|
}
|
|
|
|
|
|
read_unlock(&l->lock);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
@@ -2207,9 +2241,7 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
|
|
{
|
|
|
struct l2cap_chan_list *l;
|
|
|
struct l2cap_conn *conn = hcon->l2cap_data;
|
|
|
- struct l2cap_conn_rsp rsp;
|
|
|
struct sock *sk;
|
|
|
- int result;
|
|
|
|
|
|
if (!conn)
|
|
|
return 0;
|
|
@@ -2234,34 +2266,46 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- if (sk->sk_state != BT_CONNECT2) {
|
|
|
- bh_unlock_sock(sk);
|
|
|
- continue;
|
|
|
- }
|
|
|
+ if (sk->sk_state == BT_CONNECT) {
|
|
|
+ if (!status) {
|
|
|
+ struct l2cap_conn_req req;
|
|
|
+ req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
+ req.psm = l2cap_pi(sk)->psm;
|
|
|
|
|
|
- if (!status) {
|
|
|
- sk->sk_state = BT_CONFIG;
|
|
|
- result = 0;
|
|
|
- } else {
|
|
|
- sk->sk_state = BT_DISCONN;
|
|
|
- l2cap_sock_set_timer(sk, HZ/10);
|
|
|
- result = L2CAP_CR_SEC_BLOCK;
|
|
|
- }
|
|
|
+ l2cap_pi(sk)->ident = l2cap_get_ident(conn);
|
|
|
|
|
|
- rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
|
|
|
- rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
- rsp.result = cpu_to_le16(result);
|
|
|
- rsp.status = cpu_to_le16(0);
|
|
|
- l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
- L2CAP_CONN_RSP, sizeof(rsp), &rsp);
|
|
|
+ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
+ L2CAP_CONN_REQ, sizeof(req), &req);
|
|
|
+ } else {
|
|
|
+ l2cap_sock_clear_timer(sk);
|
|
|
+ l2cap_sock_set_timer(sk, HZ / 10);
|
|
|
+ }
|
|
|
+ } else if (sk->sk_state == BT_CONNECT2) {
|
|
|
+ struct l2cap_conn_rsp rsp;
|
|
|
+ __u16 result;
|
|
|
|
|
|
- if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE)
|
|
|
- hci_conn_change_link_key(hcon);
|
|
|
+ if (!status) {
|
|
|
+ sk->sk_state = BT_CONFIG;
|
|
|
+ result = L2CAP_CR_SUCCESS;
|
|
|
+ } else {
|
|
|
+ sk->sk_state = BT_DISCONN;
|
|
|
+ l2cap_sock_set_timer(sk, HZ / 10);
|
|
|
+ result = L2CAP_CR_SEC_BLOCK;
|
|
|
+ }
|
|
|
+
|
|
|
+ rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
|
|
|
+ rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
|
|
|
+ rsp.result = cpu_to_le16(result);
|
|
|
+ rsp.status = cpu_to_le16(0);
|
|
|
+ l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
|
|
|
+ L2CAP_CONN_RSP, sizeof(rsp), &rsp);
|
|
|
+ }
|
|
|
|
|
|
bh_unlock_sock(sk);
|
|
|
}
|
|
|
|
|
|
read_unlock(&l->lock);
|
|
|
+
|
|
|
return 0;
|
|
|
}
|
|
|
|