diff options
| -rw-r--r-- | include/linux/dccp.h | 1 | ||||
| -rw-r--r-- | net/dccp/input.c | 88 | ||||
| -rw-r--r-- | net/dccp/proto.c | 88 |
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 | ||
| 265 | enum { | 264 | enum { |
| 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 | ||
| 35 | static void dccp_rcv_close(struct sock *sk, struct sk_buff *skb) | 35 | static 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 | ||
| 43 | static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb) | 81 | static 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 | ||
| 61 | static u8 dccp_reset_code_convert(const u8 code) | 115 | static 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 | ||
| 93 | EXPORT_SYMBOL_GPL(dccp_set_state); | 94 | EXPORT_SYMBOL_GPL(dccp_set_state); |
| 94 | 95 | ||
| 96 | static 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 | |||
| 95 | void dccp_done(struct sock *sk) | 114 | void 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); | ||
| 778 | verify_sock_status: | 804 | verify_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 | ||
| 877 | EXPORT_SYMBOL_GPL(inet_dccp_listen); | 903 | EXPORT_SYMBOL_GPL(inet_dccp_listen); |
| 878 | 904 | ||
| 879 | static const unsigned char dccp_new_state[] = { | 905 | static 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 | |||
| 892 | static 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 | ||
| 903 | void dccp_close(struct sock *sk, long timeout) | 931 | void 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); |
