Commit d8ef2c29 authored by Gerrit Renker's avatar Gerrit Renker Committed by Arnaldo Carvalho de Melo

[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: default avatarGerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: default avatarIan McDonald <ian.mcdonald@jandi.co.nz>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 1238d087
...@@ -144,6 +144,8 @@ enum dccp_reset_codes { ...@@ -144,6 +144,8 @@ enum dccp_reset_codes {
DCCP_RESET_CODE_TOO_BUSY, DCCP_RESET_CODE_TOO_BUSY,
DCCP_RESET_CODE_BAD_INIT_COOKIE, DCCP_RESET_CODE_BAD_INIT_COOKIE,
DCCP_RESET_CODE_AGGRESSION_PENALTY, DCCP_RESET_CODE_AGGRESSION_PENALTY,
DCCP_MAX_RESET_CODES /* Leave at the end! */
}; };
/* DCCP options */ /* DCCP options */
......
...@@ -58,6 +58,42 @@ static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb) ...@@ -58,6 +58,42 @@ static void dccp_rcv_closereq(struct sock *sk, struct sk_buff *skb)
dccp_send_close(sk, 0); dccp_send_close(sk, 0);
} }
static u8 dccp_reset_code_convert(const u8 code)
{
const u8 error_code[] = {
[DCCP_RESET_CODE_CLOSED] = 0, /* normal termination */
[DCCP_RESET_CODE_UNSPECIFIED] = 0, /* nothing known */
[DCCP_RESET_CODE_ABORTED] = ECONNRESET,
[DCCP_RESET_CODE_NO_CONNECTION] = ECONNREFUSED,
[DCCP_RESET_CODE_CONNECTION_REFUSED] = ECONNREFUSED,
[DCCP_RESET_CODE_TOO_BUSY] = EUSERS,
[DCCP_RESET_CODE_AGGRESSION_PENALTY] = EDQUOT,
[DCCP_RESET_CODE_PACKET_ERROR] = ENOMSG,
[DCCP_RESET_CODE_BAD_INIT_COOKIE] = EBADR,
[DCCP_RESET_CODE_BAD_SERVICE_CODE] = EBADRQC,
[DCCP_RESET_CODE_OPTION_ERROR] = EILSEQ,
[DCCP_RESET_CODE_MANDATORY_ERROR] = EOPNOTSUPP,
};
return code >= DCCP_MAX_RESET_CODES ? 0 : error_code[code];
}
static void dccp_rcv_reset(struct sock *sk, struct sk_buff *skb)
{
u8 err = dccp_reset_code_convert(dccp_hdr_reset(skb)->dccph_reset_code);
sk->sk_err = err;
/* Queue the equivalent of TCP fin so that dccp_recvmsg exits the loop */
dccp_fin(sk, skb);
if (err && !sock_flag(sk, SOCK_DEAD))
sk_wake_async(sk, 0, POLL_ERR);
dccp_time_wait(sk, DCCP_TIME_WAIT, 0);
}
static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb)
{ {
struct dccp_sock *dp = dccp_sk(sk); struct dccp_sock *dp = dccp_sk(sk);
...@@ -192,8 +228,7 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb, ...@@ -192,8 +228,7 @@ static int __dccp_rcv_established(struct sock *sk, struct sk_buff *skb,
* Set TIMEWAIT timer * Set TIMEWAIT timer
* Drop packet and return * Drop packet and return
*/ */
dccp_fin(sk, skb); dccp_rcv_reset(sk, skb);
dccp_time_wait(sk, DCCP_TIME_WAIT, 0);
return 0; return 0;
case DCCP_PKT_CLOSEREQ: case DCCP_PKT_CLOSEREQ:
dccp_rcv_closereq(sk, skb); dccp_rcv_closereq(sk, skb);
...@@ -521,12 +556,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, ...@@ -521,12 +556,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* Drop packet and return * Drop packet and return
*/ */
if (dh->dccph_type == DCCP_PKT_RESET) { if (dh->dccph_type == DCCP_PKT_RESET) {
/* dccp_rcv_reset(sk, skb);
* Queue the equivalent of TCP fin so that dccp_recvmsg
* exits the loop
*/
dccp_fin(sk, skb);
dccp_time_wait(sk, DCCP_TIME_WAIT, 0);
return 0; return 0;
/* /*
* Step 7: Check for unexpected packet types * Step 7: Check for unexpected packet types
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment