Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64cf1e5d authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller
Browse files

[DCCP]: Finish the TIMEWAIT minisock support



Using most of the infrastructure TCP uses, with a dccp_death_row,
etc. As per my current interpretation of the draft what we have with
this changeset seems to be all we need (or very close to it 8)).

Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 696ab2d3
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -194,6 +194,7 @@ enum {
#include <linux/workqueue.h>

#include <net/inet_connection_sock.h>
#include <net/inet_timewait_sock.h>
#include <net/sock.h>
#include <net/tcp_states.h>
#include <net/tcp.h>
@@ -354,6 +355,8 @@ static inline struct dccp_request_sock *dccp_rsk(const struct request_sock *req)
	return (struct dccp_request_sock *)req;
}

extern struct inet_timewait_death_row dccp_death_row;

/* Read about the ECN nonce to see why it is 253 */
#define DCCP_MAX_ACK_VECTOR_LEN 253

+10 −5
Original line number Diff line number Diff line
@@ -97,7 +97,7 @@ static int __dccp_v4_check_established(struct sock *sk, const __u16 lport,
		NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);
	} else if (tw != NULL) {
		/* Silly. Should hash-dance instead... */
		dccp_tw_deschedule(tw);
		inet_twsk_deschedule(tw, &dccp_death_row);
		NET_INC_STATS_BH(LINUX_MIB_TIMEWAITRECYCLED);

		inet_twsk_put(tw);
@@ -201,7 +201,7 @@ ok:
 		spin_unlock(&head->lock);

 		if (tw != NULL) {
 			dccp_tw_deschedule(tw);
 			inet_twsk_deschedule(tw, &dccp_death_row);
 			inet_twsk_put(tw);
 		}

@@ -1131,8 +1131,9 @@ int dccp_v4_rcv(struct sk_buff *skb)
	 */
	       
	if (sk->sk_state == DCCP_TIME_WAIT) {
		dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: discard_and_relse\n");
                goto discard_and_relse;
		dccp_pr_debug("sk->sk_state == DCCP_TIME_WAIT: "
			      "do_time_wait\n");
                goto do_time_wait;
	}

	if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) {
@@ -1179,6 +1180,10 @@ discard_it:
discard_and_relse:
	sock_put(sk);
	goto discard_it;

do_time_wait:
	inet_twsk_put((struct inet_timewait_sock *)sk);
	goto no_dccp_socket;
}

static int dccp_v4_init_sock(struct sock *sk)
@@ -1290,5 +1295,5 @@ struct proto dccp_v4_prot = {
	.max_header		= MAX_DCCP_HEADER,
	.obj_size		= sizeof(struct dccp_sock),
	.rsk_prot		= &dccp_request_sock_ops,
	.twsk_obj_size		= sizeof(struct inet_timewait_sock), /* FIXME! create dccp_timewait_sock */
	.twsk_obj_size		= sizeof(struct inet_timewait_sock),
};
+50 −10
Original line number Diff line number Diff line
@@ -22,18 +22,58 @@
#include "ccid.h"
#include "dccp.h"

struct inet_timewait_death_row dccp_death_row = {
	.sysctl_max_tw_buckets = NR_FILE * 2,
	.period		= DCCP_TIMEWAIT_LEN / INET_TWDR_TWKILL_SLOTS,
	.death_lock	= SPIN_LOCK_UNLOCKED,
	.hashinfo	= &dccp_hashinfo,
	.tw_timer	= TIMER_INITIALIZER(inet_twdr_hangman, 0,
					    (unsigned long)&dccp_death_row),
	.twkill_work	= __WORK_INITIALIZER(dccp_death_row.twkill_work,
					     inet_twdr_twkill_work,
					     &dccp_death_row),
/* Short-time timewait calendar */

	.twcal_hand	= -1,
	.twcal_timer	= TIMER_INITIALIZER(inet_twdr_twcal_tick, 0,
					    (unsigned long)&dccp_death_row),
};

void dccp_time_wait(struct sock *sk, int state, int timeo)
{
	/* FIXME: Implement */
	dccp_pr_debug("Want to help? Start here\n");
	dccp_set_state(sk, state);
	struct inet_timewait_sock *tw = NULL;

	if (dccp_death_row.tw_count < dccp_death_row.sysctl_max_tw_buckets)
		tw = inet_twsk_alloc(sk, state);

	if (tw != NULL) {
		const struct inet_connection_sock *icsk = inet_csk(sk);
		const int rto = (icsk->icsk_rto << 2) - (icsk->icsk_rto >> 1);

		/* Linkage updates. */
		__inet_twsk_hashdance(tw, sk, &dccp_hashinfo);

		/* Get the TIME_WAIT timeout firing. */
		if (timeo < rto)
			timeo = rto;

		tw->tw_timeout = DCCP_TIMEWAIT_LEN;
		if (state == DCCP_TIME_WAIT)
			timeo = DCCP_TIMEWAIT_LEN;

		inet_twsk_schedule(tw, &dccp_death_row, timeo,
				   DCCP_TIMEWAIT_LEN);
		inet_twsk_put(tw);
	} else {
		/* Sorry, if we're out of memory, just CLOSE this
		 * socket up.  We've got bigger problems than
		 * non-graceful socket closings.
		 */
		if (net_ratelimit())
			printk(KERN_INFO "DCCP: time wait bucket table overflow\n");
	}

/* This is for handling early-kills of TIME_WAIT sockets. */
void dccp_tw_deschedule(struct inet_timewait_sock *tw)
{
	dccp_pr_debug("Want to help? Start here\n");
	__inet_twsk_kill(tw, &dccp_hashinfo);
	dccp_done(sk);
}

struct sock *dccp_create_openreq_child(struct sock *sk,
@@ -55,7 +95,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk,

		newdp->dccps_hc_rx_ackpkts = NULL;
		newdp->dccps_role = DCCP_ROLE_SERVER;
		newicsk->icsk_rto = TCP_TIMEOUT_INIT;
		newicsk->icsk_rto = DCCP_TIMEOUT_INIT;

		if (newdp->dccps_options.dccpo_send_ack_vector) {
			newdp->dccps_hc_rx_ackpkts = dccp_ackpkts_alloc(DCCP_MAX_ACK_VECTOR_LEN,