aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2007-11-28 08:59:48 -0500
committerDavid S. Miller <davem@davemloft.net>2008-01-28 17:55:13 -0500
commit0c869620762fea4b3acf6502d9e80840b27ec642 (patch)
tree218146397018baf917260f3d0a90dd89fc13cc7f /net/dccp
parentf11135a3442996d78dad99933bfdb90d1f6588d3 (diff)
[DCCP]: Integrate state transitions for passive-close
This adds the necessary state transitions for the two forms of passive-close * PASSIVE_CLOSE - which is entered when a host receives a Close; * PASSIVE_CLOSEREQ - which is entered when a client receives a CloseReq. Here is a detailed account of what the patch does in each state. 1) Receiving CloseReq The pseudo-code in 8.5 says: Step 13: Process CloseReq If P.type == CloseReq and S.state < CLOSEREQ, Generate Close S.state := CLOSING Set CLOSING timer. This means we need to address what to do in CLOSED, LISTEN, REQUEST, RESPOND, PARTOPEN, and OPEN. * CLOSED: silently ignore - it may be a late or duplicate CloseReq; * LISTEN/RESPOND: will not appear, since Step 7 is performed first (we know we are the client); * REQUEST: perform Step 13 directly (no need to enqueue packet); * OPEN/PARTOPEN: enter PASSIVE_CLOSEREQ so that the application has a chance to process unread data. When already in PASSIVE_CLOSEREQ, no second CloseReq is enqueued. In any other state, the CloseReq is ignored. I think that this offers some robustness against rare and pathological cases: e.g. a simultaneous close where the client sends a Close and the server a CloseReq. The client will then be retransmitting its Close until it gets the Reset, so ignoring the CloseReq while in state CLOSING is sane. 2) Receiving Close The code below from 8.5 is unconditional. Step 14: Process Close If P.type == Close, Generate Reset(Closed) Tear down connection Drop packet and return Thus we need to consider all states: * CLOSED: silently ignore, since this can happen when a retransmitted or late Close arrives; * LISTEN: dccp_rcv_state_process() will generate a Reset ("No Connection"); * REQUEST: perform Step 14 directly (no need to enqueue packet); * RESPOND: dccp_check_req() will generate a Reset ("Packet Error") -- left it at that; * OPEN/PARTOPEN: enter PASSIVE_CLOSE so that application has a chance to process unread data; * CLOSEREQ: server performed active-close -- perform Step 14; * CLOSING: simultaneous-close: use a tie-breaker to avoid message ping-pong (see comment); * PASSIVE_CLOSEREQ: ignore - the peer has a bug (sending first a CloseReq and now a Close); * TIMEWAIT: packet is ignored. Note that the condition of receiving a packet in state CLOSED here is different from the condition "there is no socket for such a connection": the socket still exists, but its state indicates it is unusable. Last, dccp_finish_passive_close sets either DCCP_CLOSED or DCCP_CLOSING = TCP_CLOSING, so that sk_stream_wait_close() will wait for the final Reset (which will trigger CLOSING => CLOSED). Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp')
-rw-r--r--net/dccp/input.c88
-rw-r--r--net/dccp/proto.c88
2 files changed, 131 insertions, 45 deletions
diff --git a/net/dccp/input.c b/net/dccp/input.c
index ef299fbd7c26..fe4b0fbfa508 100644
--- a/net/dccp/input.c
+++ b/net/dccp/input.c
@@ -32,16 +32,56 @@ static void dccp_fin(struct sock *sk, struct sk_buff *skb)
32 sk->sk_data_ready(sk, 0); 32 sk->sk_data_ready(sk, 0);
33} 33}
34 34
35static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb) 35static int dccp_rcv_close(struct sock *sk, struct sk_buff *skb)
36{ 36{
37 dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED); 37 int queued = 0;
38 dccp_fin(sk, skb); 38
39 dccp_set_state(sk, DCCP_CLOSED); 39 switch (sk->sk_state) {
40 sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP); 40 /*
41 * We ignore Close when received in one of the following states:
42 * - CLOSED (may be a late or duplicate packet)
43 * - PASSIVE_CLOSEREQ (the peer has sent a CloseReq earlier)
44 * - RESPOND (already handled by dccp_check_req)
45 */
46 case DCCP_CLOSING:
47 /*
48 * Simultaneous-close: receiving a Close after sending one. This
49 * can happen if both client and server perform active-close and
50 * will result in an endless ping-pong of crossing and retrans-
51 * mitted Close packets, which only terminates when one of the
52 * nodes times out (min. 64 seconds). Quicker convergence can be
53 * achieved when one of the nodes acts as tie-breaker.
54 * This is ok as both ends are done with data transfer and each
55 * end is just waiting for the other to acknowledge termination.
56 */
57 if (dccp_sk(sk)->dccps_role != DCCP_ROLE_CLIENT)
58 break;
59 /* fall through */
60 case DCCP_REQUESTING:
61 case DCCP_ACTIVE_CLOSEREQ:
62 dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
63 dccp_done(sk);
64 break;
65 case DCCP_OPEN:
66 case DCCP_PARTOPEN:
67 /* Give waiting application a chance to read pending data */
68 queued = 1;
69 dccp_fin(sk, skb);
70 dccp_set_state(sk, DCCP_PASSIVE_CLOSE);
71 /* fall through */
72 case DCCP_PASSIVE_CLOSE:
73 /*
74 * Retransmitted Close: we have already enqueued the first one.
75 */
76 sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP);
77 }
78 return queued;
41} 79}
42 80
43static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb) 81static int dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
44{ 82{
83 int queued = 0;
84
45 /* 85 /*
46 * Step 7: Check for unexpected packet types 86 * Step 7: Check for unexpected packet types
47 * If (S.is_server and P.type == CloseReq) 87 * If (S.is_server and P.type == CloseReq)
@@ -50,12 +90,26 @@ static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
50 */ 90 */
51 if (dccp_sk(sk)->dccps_role != DCCP_ROLE_CLIENT) { 91 if (dccp_sk(sk)->dccps_role != DCCP_ROLE_CLIENT) {
52 dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_PKT_SYNC); 92 dccp_send_sync(sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_PKT_SYNC);
53 return; 93 return queued;
54 } 94 }
55 95
56 if (sk->sk_state != DCCP_CLOSING) 96 /* Step 13: process relevant Client states < CLOSEREQ */
97 switch (sk->sk_state) {
98 case DCCP_REQUESTING:
99 dccp_send_close(sk, 0);
57 dccp_set_state(sk, DCCP_CLOSING); 100 dccp_set_state(sk, DCCP_CLOSING);
58 dccp_send_close(sk, 0); 101 break;
102 case DCCP_OPEN:
103 case DCCP_PARTOPEN:
104 /* Give waiting application a chance to read pending data */
105 queued = 1;
106 dccp_fin(sk, skb);
107 dccp_set_state(sk, DCCP_PASSIVE_CLOSEREQ);
108 /* fall through */
109 case DCCP_PASSIVE_CLOSEREQ:
110 sk_wake_async(sk, SOCK_WAKE_WAITD, POLL_HUP);
111 }
112 return queued;
59} 113}
60 114
61static u8 dccp_reset_code_convert(const u8 code) 115static u8 dccp_reset_code_convert(const u8 code)
@@ -247,11 +301,13 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
247 dccp_rcv_reset(sk, skb); 301 dccp_rcv_reset(sk, skb);
248 return 0; 302 return 0;
249 case DCCP_PKT_CLOSEREQ: 303 case DCCP_PKT_CLOSEREQ:
250 dccp_rcv_closereq(sk, skb); 304 if (dccp_rcv_closereq(sk, skb))
305 return 0;
251 goto discard; 306 goto discard;
252 case DCCP_PKT_CLOSE: 307 case DCCP_PKT_CLOSE:
253 dccp_rcv_close(sk, skb); 308 if (dccp_rcv_close(sk, skb))
254 return 0; 309 return 0;
310 goto discard;
255 case DCCP_PKT_REQUEST: 311 case DCCP_PKT_REQUEST:
256 /* Step 7 312 /* Step 7
257 * or (S.is_server and P.type == Response) 313 * or (S.is_server and P.type == Response)
@@ -590,11 +646,13 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
590 dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNC); 646 dccp_send_sync(sk, dcb->dccpd_seq, DCCP_PKT_SYNC);
591 goto discard; 647 goto discard;
592 } else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) { 648 } else if (dh->dccph_type == DCCP_PKT_CLOSEREQ) {
593 dccp_rcv_closereq(sk, skb); 649 if (dccp_rcv_closereq(sk, skb))
650 return 0;
594 goto discard; 651 goto discard;
595 } else if (dh->dccph_type == DCCP_PKT_CLOSE) { 652 } else if (dh->dccph_type == DCCP_PKT_CLOSE) {
596 dccp_rcv_close(sk, skb); 653 if (dccp_rcv_close(sk, skb))
597 return 0; 654 return 0;
655 goto discard;
598 } 656 }
599 657
600 switch (sk->sk_state) { 658 switch (sk->sk_state) {
diff --git a/net/dccp/proto.c b/net/dccp/proto.c
index 3489d3f21f50..60f40ec72ff3 100644
--- a/net/dccp/proto.c
+++ b/net/dccp/proto.c
@@ -71,7 +71,8 @@ void dccp_set_state(struct sock *sk, const int state)
71 break; 71 break;
72 72
73 case DCCP_CLOSED: 73 case DCCP_CLOSED:
74 if (oldstate == DCCP_CLOSING || oldstate == DCCP_OPEN) 74 if (oldstate == DCCP_OPEN || oldstate == DCCP_ACTIVE_CLOSEREQ ||
75 oldstate == DCCP_CLOSING)
75 DCCP_INC_STATS(DCCP_MIB_ESTABRESETS); 76 DCCP_INC_STATS(DCCP_MIB_ESTABRESETS);
76 77
77 sk->sk_prot->unhash(sk); 78 sk->sk_prot->unhash(sk);
@@ -92,6 +93,24 @@ void dccp_set_state(struct sock *sk, const int state)
92 93
93EXPORT_SYMBOL_GPL(dccp_set_state); 94EXPORT_SYMBOL_GPL(dccp_set_state);
94 95
96static void dccp_finish_passive_close(struct sock *sk)
97{
98 switch (sk->sk_state) {
99 case DCCP_PASSIVE_CLOSE:
100 /* Node (client or server) has received Close packet. */
101 dccp_send_reset(sk, DCCP_RESET_CODE_CLOSED);
102 dccp_set_state(sk, DCCP_CLOSED);
103 break;
104 case DCCP_PASSIVE_CLOSEREQ:
105 /*
106 * Client received CloseReq. We set the `active' flag so that
107 * dccp_send_close() retransmits the Close as per RFC 4340, 8.3.
108 */
109 dccp_send_close(sk, 1);
110 dccp_set_state(sk, DCCP_CLOSING);
111 }
112}
113
95void dccp_done(struct sock *sk) 114void dccp_done(struct sock *sk)
96{ 115{
97 dccp_set_state(sk, DCCP_CLOSED); 116 dccp_set_state(sk, DCCP_CLOSED);
@@ -762,19 +781,26 @@ int dccp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
762 781
763 dh = dccp_hdr(skb); 782 dh = dccp_hdr(skb);
764 783
765 if (dh->dccph_type == DCCP_PKT_DATA || 784 switch (dh->dccph_type) {
766 dh->dccph_type == DCCP_PKT_DATAACK) 785 case DCCP_PKT_DATA:
786 case DCCP_PKT_DATAACK:
767 goto found_ok_skb; 787 goto found_ok_skb;
768 788
769 if (dh->dccph_type == DCCP_PKT_RESET || 789 case DCCP_PKT_CLOSE:
770 dh->dccph_type == DCCP_PKT_CLOSE) { 790 case DCCP_PKT_CLOSEREQ:
771 dccp_pr_debug("found fin ok!\n"); 791 if (!(flags & MSG_PEEK))
792 dccp_finish_passive_close(sk);
793 /* fall through */
794 case DCCP_PKT_RESET:
795 dccp_pr_debug("found fin (%s) ok!\n",
796 dccp_packet_name(dh->dccph_type));
772 len = 0; 797 len = 0;
773 goto found_fin_ok; 798 goto found_fin_ok;
799 default:
800 dccp_pr_debug("packet_type=%s\n",
801 dccp_packet_name(dh->dccph_type));
802 sk_eat_skb(sk, skb, 0);
774 } 803 }
775 dccp_pr_debug("packet_type=%s\n",
776 dccp_packet_name(dh->dccph_type));
777 sk_eat_skb(sk, skb, 0);
778verify_sock_status: 804verify_sock_status:
779 if (sock_flag(sk, SOCK_DONE)) { 805 if (sock_flag(sk, SOCK_DONE)) {
780 len = 0; 806 len = 0;
@@ -876,28 +902,30 @@ out:
876 902
877EXPORT_SYMBOL_GPL(inet_dccp_listen); 903EXPORT_SYMBOL_GPL(inet_dccp_listen);
878 904
879static const unsigned char dccp_new_state[] = { 905static void dccp_terminate_connection(struct sock *sk)
880 /* current state: new state: action: */
881 [0] = DCCP_CLOSED,
882 [DCCP_OPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
883 [DCCP_REQUESTING] = DCCP_CLOSED,
884 [DCCP_PARTOPEN] = DCCP_CLOSING | DCCP_ACTION_FIN,
885 [DCCP_LISTEN] = DCCP_CLOSED,
886 [DCCP_RESPOND] = DCCP_CLOSED,
887 [DCCP_CLOSING] = DCCP_CLOSED,
888 [DCCP_TIME_WAIT] = DCCP_CLOSED,
889 [DCCP_CLOSED] = DCCP_CLOSED,
890};
891
892static int dccp_close_state(struct sock *sk)
893{ 906{
894 const int next = dccp_new_state[sk->sk_state]; 907 u8 next_state = DCCP_CLOSED;
895 const int ns = next & DCCP_STATE_MASK;
896 908
897 if (ns != sk->sk_state) 909 switch (sk->sk_state) {
898 dccp_set_state(sk, ns); 910 case DCCP_PASSIVE_CLOSE:
911 case DCCP_PASSIVE_CLOSEREQ:
912 dccp_finish_passive_close(sk);
913 break;
914 case DCCP_PARTOPEN:
915 dccp_pr_debug("Stop PARTOPEN timer (%p)\n", sk);
916 inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
917 /* fall through */
918 case DCCP_OPEN:
919 dccp_send_close(sk, 1);
899 920
900 return next & DCCP_ACTION_FIN; 921 if (dccp_sk(sk)->dccps_role == DCCP_ROLE_SERVER)
922 next_state = DCCP_ACTIVE_CLOSEREQ;
923 else
924 next_state = DCCP_CLOSING;
925 /* fall through */
926 default:
927 dccp_set_state(sk, next_state);
928 }
901} 929}
902 930
903void dccp_close(struct sock *sk, long timeout) 931void dccp_close(struct sock *sk, long timeout)
@@ -940,8 +968,8 @@ void dccp_close(struct sock *sk, long timeout)
940 } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { 968 } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) {
941 /* Check zero linger _after_ checking for unread data. */ 969 /* Check zero linger _after_ checking for unread data. */
942 sk->sk_prot->disconnect(sk, 0); 970 sk->sk_prot->disconnect(sk, 0);
943 } else if (dccp_close_state(sk)) { 971 } else if (sk->sk_state != DCCP_CLOSED) {
944 dccp_send_close(sk, 1); 972 dccp_terminate_connection(sk);
945 } 973 }
946 974
947 sk_stream_wait_close(sk, timeout); 975 sk_stream_wait_close(sk, timeout);