diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2007-10-24 08:27:48 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@ghostprotocols.net> | 2007-10-24 08:27:48 -0400 |
commit | d8ef2c29a0dcfccb2d90cac990143d1a4668708a (patch) | |
tree | f84aa65931c586117958718b23aa209136719372 | |
parent | 1238d0873b29f7a2de75d576b4cc706c1c75ffbf (diff) |
[DCCP]: Convert Reset code into socket error number
This adds support for converting the 11 currently defined Reset codes into system
error numbers, which are stored in sk_err for further interpretation.
This makes the externally visible API behaviour similar to TCP, since a client
connecting to a non-existing port will experience ECONNREFUSED.
* Code 0, Unspecified, is interpreted as non-error (0);
* Code 1, Closed (normal termination), also maps into 0;
* Code 2, Aborted, maps into "Connection reset by peer" (ECONNRESET);
* Code 3, No Connection and
Code 7, Connection Refused, map into "Connection refused" (ECONNREFUSED);
* Code 4, Packet Error, maps into "No message of desired type" (ENOMSG);
* Code 5, Option Error, maps into "Illegal byte sequence" (EILSEQ);
* Code 6, Mandatory Error, maps into "Operation not supported on transport endpoint" (EOPNOTSUPP);
* Code 8, Bad Service Code, maps into "Invalid request code" (EBADRQC);
* Code 9, Too Busy, maps into "Too many users" (EUSERS);
* Code 10, Bad Init Cookie, maps into "Invalid request descriptor" (EBADR);
* Code 11, Aggression Penalty, maps into "Quota exceeded" (EDQUOT)
which makes sense in terms of using more than the `fair share' of bandwidth.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-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 |