diff options
Diffstat (limited to 'net/dccp/input.c')
| -rw-r--r-- | net/dccp/input.c | 48 |
1 files changed, 39 insertions, 9 deletions
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 |
