aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/dccp.h1
-rw-r--r--net/dccp/input.c88
-rw-r--r--net/dccp/proto.c88
3 files changed, 131 insertions, 46 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h
index 8b3f9ad3cf04..312b989c7edb 100644
--- a/include/linux/dccp.h
+++ b/include/linux/dccp.h
@@ -260,7 +260,6 @@ enum dccp_state {
260}; 260};
261 261
262#define DCCP_STATE_MASK 0x1f 262#define DCCP_STATE_MASK 0x1f
263#define DCCP_ACTION_FIN (1<<7)
264 263
265enum { 264enum {
266 DCCPF_OPEN = TCPF_ESTABLISHED, 265 DCCPF_OPEN = TCPF_ESTABLISHED,
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);