diff options
-rw-r--r-- | include/linux/dccp.h | 2 | ||||
-rw-r--r-- | net/dccp/input.c | 48 |
2 files changed, 41 insertions, 9 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 55d28cb97596..333c3ea82a5d 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -144,6 +144,8 @@ enum dccp_reset_codes { | |||
144 | DCCP_RESET_CODE_TOO_BUSY, | 144 | DCCP_RESET_CODE_TOO_BUSY, |
145 | DCCP_RESET_CODE_BAD_INIT_COOKIE, | 145 | DCCP_RESET_CODE_BAD_INIT_COOKIE, |
146 | DCCP_RESET_CODE_AGGRESSION_PENALTY, | 146 | DCCP_RESET_CODE_AGGRESSION_PENALTY, |
147 | |||
148 | DCCP_MAX_RESET_CODES /* Leave at the end! */ | ||
147 | }; | 149 | }; |
148 | 150 | ||
149 | /* DCCP options */ | 151 | /* DCCP options */ |
diff --git a/net/dccp/input.c b/net/dccp/input.c index 3560a2a875a0..1ce101062824 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c | |||
@@ -58,6 +58,42 @@ static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb) | |||
58 | dccp_send_close(sk, 0); | 58 | dccp_send_close(sk, 0); |
59 | } | 59 | } |
60 | 60 | ||
61 | static u8 dccp_reset_code_convert(const u8 code) | ||
62 | { | ||
63 | const u8 error_code[] = { | ||
64 | [DCCP_RESET_CODE_CLOSED] = 0, /* normal termination */ | ||
65 | [DCCP_RESET_CODE_UNSPECIFIED] = 0, /* nothing known */ | ||
66 | [DCCP_RESET_CODE_ABORTED] = ECONNRESET, | ||
67 | |||
68 | [DCCP_RESET_CODE_NO_CONNECTION] = ECONNREFUSED, | ||
69 | [DCCP_RESET_CODE_CONNECTION_REFUSED] = ECONNREFUSED, | ||
70 | [DCCP_RESET_CODE_TOO_BUSY] = EUSERS, | ||
71 | [DCCP_RESET_CODE_AGGRESSION_PENALTY] = EDQUOT, | ||
72 | |||
73 | [DCCP_RESET_CODE_PACKET_ERROR] = ENOMSG, | ||
74 | [DCCP_RESET_CODE_BAD_INIT_COOKIE] = EBADR, | ||
75 | [DCCP_RESET_CODE_BAD_SERVICE_CODE] = EBADRQC, | ||
76 | [DCCP_RESET_CODE_OPTION_ERROR] = EILSEQ, | ||
77 | [DCCP_RESET_CODE_MANDATORY_ERROR] = EOPNOTSUPP, | ||
78 | }; | ||
79 | |||
80 | return code >= DCCP_MAX_RESET_CODES ? 0 : error_code[code]; | ||
81 | } | ||
82 | |||
83 | static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb) | ||
84 | { | ||
85 | u8 err = dccp_reset_code_convert(dccp_hdr_reset(skb)->dccph_reset_code); | ||
86 | |||
87 | sk->sk_err = err; | ||
88 | |||
89 | /* Queue the equivalent of TCP fin so that dccp_recvmsg exits the loop */ | ||
90 | dccp_fin(sk, skb); | ||
91 | |||
92 | if (err && !sock_flag(sk, SOCK_DEAD)) | ||
93 | sk_wake_async(sk, 0, POLL_ERR); | ||
94 | dccp_time_wait(sk, DCCP_TIME_WAIT, 0); | ||
95 | } | ||
96 | |||
61 | static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) | 97 | static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) |
62 | { | 98 | { |
63 | struct dccp_sock *dp = dccp_sk(sk); | 99 | struct dccp_sock *dp = dccp_sk(sk); |
@@ -191,9 +227,8 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
191 | * S.state := TIMEWAIT | 227 | * S.state := TIMEWAIT |
192 | * Set TIMEWAIT timer | 228 | * Set TIMEWAIT timer |
193 | * Drop packet and return | 229 | * Drop packet and return |
194 | */ | 230 | */ |
195 | dccp_fin(sk, skb); | 231 | dccp_rcv_reset(sk, skb); |
196 | dccp_time_wait(sk, DCCP_TIME_WAIT, 0); | ||
197 | return 0; | 232 | return 0; |
198 | case DCCP_PKT_CLOSEREQ: | 233 | case DCCP_PKT_CLOSEREQ: |
199 | dccp_rcv_closereq(sk, skb); | 234 | dccp_rcv_closereq(sk, skb); |
@@ -521,12 +556,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
521 | * Drop packet and return | 556 | * Drop packet and return |
522 | */ | 557 | */ |
523 | if (dh->dccph_type == DCCP_PKT_RESET) { | 558 | if (dh->dccph_type == DCCP_PKT_RESET) { |
524 | /* | 559 | dccp_rcv_reset(sk, skb); |
525 | * Queue the equivalent of TCP fin so that dccp_recvmsg | ||
526 | * exits the loop | ||
527 | */ | ||
528 | dccp_fin(sk, skb); | ||
529 | dccp_time_wait(sk, DCCP_TIME_WAIT, 0); | ||
530 | return 0; | 560 | return 0; |
531 | /* | 561 | /* |
532 | * Step 7: Check for unexpected packet types | 562 | * Step 7: Check for unexpected packet types |