diff options
author | David S. Miller <davem@davemloft.net> | 2017-04-28 12:20:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2017-04-28 12:20:43 -0400 |
commit | c51847171162212618b3227812f007a654de2f4b (patch) | |
tree | 105f419e4111501b0aee0067d9d566776d07dbc3 | |
parent | f83246089ca09308425175d47f5e71e6da68b2ef (diff) | |
parent | c1be7756284b0fdbfe8aea8da968ce054697e0c5 (diff) |
Merge branch 'tipc-socket-connection-hangs'
Parthasarathy Bhuvaragan says:
====================
tipc: fix hanging socket connections
This patch series contains fixes for the socket layer to
prevent hanging / stale connections.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/tipc/socket.c | 36 |
1 files changed, 31 insertions, 5 deletions
diff --git a/net/tipc/socket.c b/net/tipc/socket.c index 566906795c8c..bdce99f9407a 100644 --- a/net/tipc/socket.c +++ b/net/tipc/socket.c | |||
@@ -866,6 +866,14 @@ static void tipc_sk_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb, | |||
866 | if (!tsk_peer_msg(tsk, hdr)) | 866 | if (!tsk_peer_msg(tsk, hdr)) |
867 | goto exit; | 867 | goto exit; |
868 | 868 | ||
869 | if (unlikely(msg_errcode(hdr))) { | ||
870 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); | ||
871 | tipc_node_remove_conn(sock_net(sk), tsk_peer_node(tsk), | ||
872 | tsk_peer_port(tsk)); | ||
873 | sk->sk_state_change(sk); | ||
874 | goto exit; | ||
875 | } | ||
876 | |||
869 | tsk->probe_unacked = false; | 877 | tsk->probe_unacked = false; |
870 | 878 | ||
871 | if (mtyp == CONN_PROBE) { | 879 | if (mtyp == CONN_PROBE) { |
@@ -1259,7 +1267,10 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) | |||
1259 | struct sock *sk = sock->sk; | 1267 | struct sock *sk = sock->sk; |
1260 | DEFINE_WAIT(wait); | 1268 | DEFINE_WAIT(wait); |
1261 | long timeo = *timeop; | 1269 | long timeo = *timeop; |
1262 | int err; | 1270 | int err = sock_error(sk); |
1271 | |||
1272 | if (err) | ||
1273 | return err; | ||
1263 | 1274 | ||
1264 | for (;;) { | 1275 | for (;;) { |
1265 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 1276 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
@@ -1281,6 +1292,10 @@ static int tipc_wait_for_rcvmsg(struct socket *sock, long *timeop) | |||
1281 | err = sock_intr_errno(timeo); | 1292 | err = sock_intr_errno(timeo); |
1282 | if (signal_pending(current)) | 1293 | if (signal_pending(current)) |
1283 | break; | 1294 | break; |
1295 | |||
1296 | err = sock_error(sk); | ||
1297 | if (err) | ||
1298 | break; | ||
1284 | } | 1299 | } |
1285 | finish_wait(sk_sleep(sk), &wait); | 1300 | finish_wait(sk_sleep(sk), &wait); |
1286 | *timeop = timeo; | 1301 | *timeop = timeo; |
@@ -1551,6 +1566,8 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) | |||
1551 | struct sock *sk = &tsk->sk; | 1566 | struct sock *sk = &tsk->sk; |
1552 | struct net *net = sock_net(sk); | 1567 | struct net *net = sock_net(sk); |
1553 | struct tipc_msg *hdr = buf_msg(skb); | 1568 | struct tipc_msg *hdr = buf_msg(skb); |
1569 | u32 pport = msg_origport(hdr); | ||
1570 | u32 pnode = msg_orignode(hdr); | ||
1554 | 1571 | ||
1555 | if (unlikely(msg_mcast(hdr))) | 1572 | if (unlikely(msg_mcast(hdr))) |
1556 | return false; | 1573 | return false; |
@@ -1558,18 +1575,28 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) | |||
1558 | switch (sk->sk_state) { | 1575 | switch (sk->sk_state) { |
1559 | case TIPC_CONNECTING: | 1576 | case TIPC_CONNECTING: |
1560 | /* Accept only ACK or NACK message */ | 1577 | /* Accept only ACK or NACK message */ |
1561 | if (unlikely(!msg_connected(hdr))) | 1578 | if (unlikely(!msg_connected(hdr))) { |
1562 | return false; | 1579 | if (pport != tsk_peer_port(tsk) || |
1580 | pnode != tsk_peer_node(tsk)) | ||
1581 | return false; | ||
1582 | |||
1583 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); | ||
1584 | sk->sk_err = ECONNREFUSED; | ||
1585 | sk->sk_state_change(sk); | ||
1586 | return true; | ||
1587 | } | ||
1563 | 1588 | ||
1564 | if (unlikely(msg_errcode(hdr))) { | 1589 | if (unlikely(msg_errcode(hdr))) { |
1565 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); | 1590 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); |
1566 | sk->sk_err = ECONNREFUSED; | 1591 | sk->sk_err = ECONNREFUSED; |
1592 | sk->sk_state_change(sk); | ||
1567 | return true; | 1593 | return true; |
1568 | } | 1594 | } |
1569 | 1595 | ||
1570 | if (unlikely(!msg_isdata(hdr))) { | 1596 | if (unlikely(!msg_isdata(hdr))) { |
1571 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); | 1597 | tipc_set_sk_state(sk, TIPC_DISCONNECTING); |
1572 | sk->sk_err = EINVAL; | 1598 | sk->sk_err = EINVAL; |
1599 | sk->sk_state_change(sk); | ||
1573 | return true; | 1600 | return true; |
1574 | } | 1601 | } |
1575 | 1602 | ||
@@ -1581,8 +1608,7 @@ static bool filter_connect(struct tipc_sock *tsk, struct sk_buff *skb) | |||
1581 | return true; | 1608 | return true; |
1582 | 1609 | ||
1583 | /* If empty 'ACK-' message, wake up sleeping connect() */ | 1610 | /* If empty 'ACK-' message, wake up sleeping connect() */ |
1584 | if (waitqueue_active(sk_sleep(sk))) | 1611 | sk->sk_data_ready(sk); |
1585 | wake_up_interruptible(sk_sleep(sk)); | ||
1586 | 1612 | ||
1587 | /* 'ACK-' message is neither accepted nor rejected: */ | 1613 | /* 'ACK-' message is neither accepted nor rejected: */ |
1588 | msg_set_dest_droppable(hdr, 1); | 1614 | msg_set_dest_droppable(hdr, 1); |