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

Commit 59435444 authored by Gerrit Renker's avatar Gerrit Renker
Browse files

dccp: Allow to distinguish original and retransmitted packets



This patch allows the sender to distinguish original and retransmitted packets,
which is in particular needed for the retransmission of DCCP-Requests:
 * the first Request uses ISS (generated in net/dccp/ip*.c), and sets GSS = ISS;
 * all retransmitted Requests use GSS' = GSS + 1, so that the n-th retransmitted
   Request has sequence number ISS + n (mod 48).

To add generic support, the patch reorganises existing code so that:
 * icsk_retransmits == 0     for the original packet and
 * icsk_retransmits = n > 0  for the n-th retransmitted packet
at the time dccp_transmit_skb() is called, via dccp_retransmit_skb().
 
Thanks to Wei Yongjun for pointing this problem out.

Further changes:
----------------
 * removed the `skb' argument from dccp_retransmit_skb(), since sk_send_head
   is used for all retransmissions (the exception is client-Acks in PARTOPEN
   state, but these do not use sk_send_head);
 * since sk_send_head always contains the original skb (via dccp_entail()),
   skb_cloned() never evaluated to true and thus pskb_copy() was never used.

Signed-off-by: default avatarGerrit Renker <gerrit@erg.abdn.ac.uk>
parent cdec7e50
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -226,7 +226,7 @@ static inline void dccp_csum_outgoing(struct sk_buff *skb)

extern void dccp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb);

extern int  dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb);
extern int  dccp_retransmit_skb(struct sock *sk);

extern void dccp_send_ack(struct sock *sk);
extern void dccp_reqsk_send_ack(struct sk_buff *sk, struct request_sock *rsk);
+16 −4
Original line number Diff line number Diff line
@@ -284,14 +284,26 @@ void dccp_write_xmit(struct sock *sk, int block)
	}
}

int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
/**
 * dccp_retransmit_skb  -  Retransmit Request, Close, or CloseReq packets
 * There are only four retransmittable packet types in DCCP:
 * - Request  in client-REQUEST  state (sec. 8.1.1),
 * - CloseReq in server-CLOSEREQ state (sec. 8.3),
 * - Close    in   node-CLOSING  state (sec. 8.3),
 * - Acks in client-PARTOPEN state (sec. 8.1.5, handled by dccp_delack_timer()).
 * This function expects sk->sk_send_head to contain the original skb.
 */
int dccp_retransmit_skb(struct sock *sk)
{
	WARN_ON(sk->sk_send_head == NULL);

	if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk) != 0)
		return -EHOSTUNREACH; /* Routing failure or similar. */

	return dccp_transmit_skb(sk, (skb_cloned(skb) ?
				      pskb_copy(skb, GFP_ATOMIC):
				      skb_clone(skb, GFP_ATOMIC)));
	/* this count is used to distinguish original and retransmitted skb */
	inet_csk(sk)->icsk_retransmits++;

	return dccp_transmit_skb(sk, skb_clone(sk->sk_send_head, GFP_ATOMIC));
}

struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
+4 −16
Original line number Diff line number Diff line
@@ -98,22 +98,12 @@ static void dccp_retransmit_timer(struct sock *sk)
		goto backoff;
	}

	/*
	 * sk->sk_send_head has to have one skb with
	 * DCCP_SKB_CB(skb)->dccpd_type set to one of the retransmittable DCCP
	 * packet types. The only packets eligible for retransmission are:
	 *	-- Requests in client-REQUEST  state (sec. 8.1.1)
	 *	-- Acks     in client-PARTOPEN state (sec. 8.1.5)
	 *	-- CloseReq in server-CLOSEREQ state (sec. 8.3)
	 *	-- Close    in   node-CLOSING  state (sec. 8.3)                */
	WARN_ON(sk->sk_send_head == NULL);

	/*
	 * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was
	 * sent, no need to retransmit, this sock is dead.
	 */
	if (dccp_write_timeout(sk))
		goto out;
		return;

	/*
	 * We want to know the number of packets retransmitted, not the
@@ -122,30 +112,28 @@ static void dccp_retransmit_timer(struct sock *sk)
	if (icsk->icsk_retransmits == 0)
		DCCP_INC_STATS_BH(DCCP_MIB_TIMEOUTS);

	if (dccp_retransmit_skb(sk, sk->sk_send_head) < 0) {
	if (dccp_retransmit_skb(sk) != 0) {
		/*
		 * Retransmission failed because of local congestion,
		 * do not backoff.
		 */
		if (icsk->icsk_retransmits == 0)
		if (--icsk->icsk_retransmits == 0)
			icsk->icsk_retransmits = 1;
		inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
					  min(icsk->icsk_rto,
					      TCP_RESOURCE_PROBE_INTERVAL),
					  DCCP_RTO_MAX);
		goto out;
		return;
	}

backoff:
	icsk->icsk_backoff++;
	icsk->icsk_retransmits++;

	icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX);
	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, icsk->icsk_rto,
				  DCCP_RTO_MAX);
	if (icsk->icsk_retransmits > sysctl_dccp_retries1)
		__sk_dst_reset(sk);
out:;
}

static void dccp_write_timer(unsigned long data)