xref: /openbmc/linux/net/dccp/output.c (revision 5cc3741d)
17c657876SArnaldo Carvalho de Melo /*
27c657876SArnaldo Carvalho de Melo  *  net/dccp/output.c
37c657876SArnaldo Carvalho de Melo  *
47c657876SArnaldo Carvalho de Melo  *  An implementation of the DCCP protocol
57c657876SArnaldo Carvalho de Melo  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>
67c657876SArnaldo Carvalho de Melo  *
77c657876SArnaldo Carvalho de Melo  *	This program is free software; you can redistribute it and/or
87c657876SArnaldo Carvalho de Melo  *	modify it under the terms of the GNU General Public License
97c657876SArnaldo Carvalho de Melo  *	as published by the Free Software Foundation; either version
107c657876SArnaldo Carvalho de Melo  *	2 of the License, or (at your option) any later version.
117c657876SArnaldo Carvalho de Melo  */
127c657876SArnaldo Carvalho de Melo 
137c657876SArnaldo Carvalho de Melo #include <linux/dccp.h>
1448918a4dSHerbert Xu #include <linux/kernel.h>
157c657876SArnaldo Carvalho de Melo #include <linux/skbuff.h>
167c657876SArnaldo Carvalho de Melo 
1714c85021SArnaldo Carvalho de Melo #include <net/inet_sock.h>
187c657876SArnaldo Carvalho de Melo #include <net/sock.h>
197c657876SArnaldo Carvalho de Melo 
20ae31c339SArnaldo Carvalho de Melo #include "ackvec.h"
217c657876SArnaldo Carvalho de Melo #include "ccid.h"
227c657876SArnaldo Carvalho de Melo #include "dccp.h"
237c657876SArnaldo Carvalho de Melo 
247c657876SArnaldo Carvalho de Melo static inline void dccp_event_ack_sent(struct sock *sk)
257c657876SArnaldo Carvalho de Melo {
267c657876SArnaldo Carvalho de Melo 	inet_csk_clear_xmit_timer(sk, ICSK_TIME_DACK);
277c657876SArnaldo Carvalho de Melo }
287c657876SArnaldo Carvalho de Melo 
29c25a18baSArnaldo Carvalho de Melo static void dccp_skb_entail(struct sock *sk, struct sk_buff *skb)
3048918a4dSHerbert Xu {
3148918a4dSHerbert Xu 	skb_set_owner_w(skb, sk);
3248918a4dSHerbert Xu 	WARN_ON(sk->sk_send_head);
3348918a4dSHerbert Xu 	sk->sk_send_head = skb;
3448918a4dSHerbert Xu }
3548918a4dSHerbert Xu 
367c657876SArnaldo Carvalho de Melo /*
377c657876SArnaldo Carvalho de Melo  * All SKB's seen here are completely headerless. It is our
387c657876SArnaldo Carvalho de Melo  * job to build the DCCP header, and pass the packet down to
397c657876SArnaldo Carvalho de Melo  * IP so it can do the same plus pass the packet off to the
407c657876SArnaldo Carvalho de Melo  * device.
417c657876SArnaldo Carvalho de Melo  */
4248918a4dSHerbert Xu static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
437c657876SArnaldo Carvalho de Melo {
447c657876SArnaldo Carvalho de Melo 	if (likely(skb != NULL)) {
457c657876SArnaldo Carvalho de Melo 		const struct inet_sock *inet = inet_sk(sk);
4657cca05aSArnaldo Carvalho de Melo 		const struct inet_connection_sock *icsk = inet_csk(sk);
477c657876SArnaldo Carvalho de Melo 		struct dccp_sock *dp = dccp_sk(sk);
487c657876SArnaldo Carvalho de Melo 		struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
497c657876SArnaldo Carvalho de Melo 		struct dccp_hdr *dh;
507c657876SArnaldo Carvalho de Melo 		/* XXX For now we're using only 48 bits sequence numbers */
51118b2c95SArnaldo Carvalho de Melo 		const u32 dccp_header_size = sizeof(*dh) +
527c657876SArnaldo Carvalho de Melo 					     sizeof(struct dccp_hdr_ext) +
537c657876SArnaldo Carvalho de Melo 					  dccp_packet_hdr_len(dcb->dccpd_type);
547c657876SArnaldo Carvalho de Melo 		int err, set_ack = 1;
557c657876SArnaldo Carvalho de Melo 		u64 ackno = dp->dccps_gsr;
567c657876SArnaldo Carvalho de Melo 
577c657876SArnaldo Carvalho de Melo 		dccp_inc_seqno(&dp->dccps_gss);
587c657876SArnaldo Carvalho de Melo 
597c657876SArnaldo Carvalho de Melo 		switch (dcb->dccpd_type) {
607c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_DATA:
617c657876SArnaldo Carvalho de Melo 			set_ack = 0;
62edc9e819SHerbert Xu 			/* fall through */
63edc9e819SHerbert Xu 		case DCCP_PKT_DATAACK:
647c657876SArnaldo Carvalho de Melo 			break;
65edc9e819SHerbert Xu 
66afe00251SAndrea Bittau 		case DCCP_PKT_REQUEST:
67afe00251SAndrea Bittau 			set_ack = 0;
68afe00251SAndrea Bittau 			/* fall through */
69afe00251SAndrea Bittau 
707c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_SYNC:
717c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_SYNCACK:
727c657876SArnaldo Carvalho de Melo 			ackno = dcb->dccpd_seq;
73edc9e819SHerbert Xu 			/* fall through */
74edc9e819SHerbert Xu 		default:
75edc9e819SHerbert Xu 			/*
76edc9e819SHerbert Xu 			 * Only data packets should come through with skb->sk
77edc9e819SHerbert Xu 			 * set.
78edc9e819SHerbert Xu 			 */
79edc9e819SHerbert Xu 			WARN_ON(skb->sk);
80edc9e819SHerbert Xu 			skb_set_owner_w(skb, sk);
817c657876SArnaldo Carvalho de Melo 			break;
827c657876SArnaldo Carvalho de Melo 		}
837c657876SArnaldo Carvalho de Melo 
8424117727SArnaldo Carvalho de Melo 		dcb->dccpd_seq = dp->dccps_gss;
852d0817d1SArnaldo Carvalho de Melo 
862d0817d1SArnaldo Carvalho de Melo 		if (dccp_insert_options(sk, skb)) {
872d0817d1SArnaldo Carvalho de Melo 			kfree_skb(skb);
882d0817d1SArnaldo Carvalho de Melo 			return -EPROTO;
892d0817d1SArnaldo Carvalho de Melo 		}
9024117727SArnaldo Carvalho de Melo 
91fda0fd6cSHerbert Xu 
927c657876SArnaldo Carvalho de Melo 		/* Build DCCP header and checksum it. */
939b42078eSGerrit Renker 		dh = dccp_zeroed_hdr(skb, dccp_header_size);
947c657876SArnaldo Carvalho de Melo 		dh->dccph_type	= dcb->dccpd_type;
957c657876SArnaldo Carvalho de Melo 		dh->dccph_sport	= inet->sport;
967c657876SArnaldo Carvalho de Melo 		dh->dccph_dport	= inet->dport;
977c657876SArnaldo Carvalho de Melo 		dh->dccph_doff	= (dccp_header_size + dcb->dccpd_opt_len) / 4;
987c657876SArnaldo Carvalho de Melo 		dh->dccph_ccval	= dcb->dccpd_ccval;
996f4e5fffSGerrit Renker 		dh->dccph_cscov = dp->dccps_pcslen;
1007c657876SArnaldo Carvalho de Melo 		/* XXX For now we're using only 48 bits sequence numbers */
1017c657876SArnaldo Carvalho de Melo 		dh->dccph_x	= 1;
1027c657876SArnaldo Carvalho de Melo 
1037c657876SArnaldo Carvalho de Melo 		dp->dccps_awh = dp->dccps_gss;
1047c657876SArnaldo Carvalho de Melo 		dccp_hdr_set_seq(dh, dp->dccps_gss);
1057c657876SArnaldo Carvalho de Melo 		if (set_ack)
1067c657876SArnaldo Carvalho de Melo 			dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), ackno);
1077c657876SArnaldo Carvalho de Melo 
1087c657876SArnaldo Carvalho de Melo 		switch (dcb->dccpd_type) {
1097c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_REQUEST:
1107690af3fSArnaldo Carvalho de Melo 			dccp_hdr_request(skb)->dccph_req_service =
11167e6b629SArnaldo Carvalho de Melo 							dp->dccps_service;
1127c657876SArnaldo Carvalho de Melo 			break;
1137c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_RESET:
1147690af3fSArnaldo Carvalho de Melo 			dccp_hdr_reset(skb)->dccph_reset_code =
1157690af3fSArnaldo Carvalho de Melo 							dcb->dccpd_reset_code;
1167c657876SArnaldo Carvalho de Melo 			break;
1177c657876SArnaldo Carvalho de Melo 		}
1187c657876SArnaldo Carvalho de Melo 
1196f4e5fffSGerrit Renker 		icsk->icsk_af_ops->send_check(sk, 0, skb);
1207c657876SArnaldo Carvalho de Melo 
1217ad07e7cSArnaldo Carvalho de Melo 		if (set_ack)
1227c657876SArnaldo Carvalho de Melo 			dccp_event_ack_sent(sk);
1237c657876SArnaldo Carvalho de Melo 
1247c657876SArnaldo Carvalho de Melo 		DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
1257c657876SArnaldo Carvalho de Melo 
12649c5bfafSHerbert Xu 		memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
12793173112SDavid S. Miller 		err = icsk->icsk_af_ops->queue_xmit(skb, sk, 0);
128b9df3cb8SGerrit Renker 		return net_xmit_eval(err);
1297c657876SArnaldo Carvalho de Melo 	}
1307c657876SArnaldo Carvalho de Melo 	return -ENOBUFS;
1317c657876SArnaldo Carvalho de Melo }
1327c657876SArnaldo Carvalho de Melo 
1337c657876SArnaldo Carvalho de Melo unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu)
1347c657876SArnaldo Carvalho de Melo {
135d83d8461SArnaldo Carvalho de Melo 	struct inet_connection_sock *icsk = inet_csk(sk);
1367c657876SArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
137d83d8461SArnaldo Carvalho de Melo 	int mss_now = (pmtu - icsk->icsk_af_ops->net_header_len -
13857cca05aSArnaldo Carvalho de Melo 		       sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext));
1397c657876SArnaldo Carvalho de Melo 
1407c657876SArnaldo Carvalho de Melo 	/* Now subtract optional transport overhead */
141d83d8461SArnaldo Carvalho de Melo 	mss_now -= icsk->icsk_ext_hdr_len;
1427c657876SArnaldo Carvalho de Melo 
1437c657876SArnaldo Carvalho de Melo 	/*
1447c657876SArnaldo Carvalho de Melo 	 * FIXME: this should come from the CCID infrastructure, where, say,
1457c657876SArnaldo Carvalho de Melo 	 * TFRC will say it wants TIMESTAMPS, ELAPSED time, etc, for now lets
1467c657876SArnaldo Carvalho de Melo 	 * put a rough estimate for NDP + TIMESTAMP + TIMESTAMP_ECHO + ELAPSED
1477c657876SArnaldo Carvalho de Melo 	 * TIME + TFRC_OPT_LOSS_EVENT_RATE + TFRC_OPT_RECEIVE_RATE + padding to
1487c657876SArnaldo Carvalho de Melo 	 * make it a multiple of 4
1497c657876SArnaldo Carvalho de Melo 	 */
1507c657876SArnaldo Carvalho de Melo 
1517c657876SArnaldo Carvalho de Melo 	mss_now -= ((5 + 6 + 10 + 6 + 6 + 6 + 3) / 4) * 4;
1527c657876SArnaldo Carvalho de Melo 
1537c657876SArnaldo Carvalho de Melo 	/* And store cached results */
154d83d8461SArnaldo Carvalho de Melo 	icsk->icsk_pmtu_cookie = pmtu;
1557c657876SArnaldo Carvalho de Melo 	dp->dccps_mss_cache = mss_now;
1567c657876SArnaldo Carvalho de Melo 
1577c657876SArnaldo Carvalho de Melo 	return mss_now;
1587c657876SArnaldo Carvalho de Melo }
1597c657876SArnaldo Carvalho de Melo 
160f21e68caSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_sync_mss);
161f21e68caSArnaldo Carvalho de Melo 
162c530cfb1SArnaldo Carvalho de Melo void dccp_write_space(struct sock *sk)
163c530cfb1SArnaldo Carvalho de Melo {
164c530cfb1SArnaldo Carvalho de Melo 	read_lock(&sk->sk_callback_lock);
165c530cfb1SArnaldo Carvalho de Melo 
166c530cfb1SArnaldo Carvalho de Melo 	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
167c530cfb1SArnaldo Carvalho de Melo 		wake_up_interruptible(sk->sk_sleep);
168c530cfb1SArnaldo Carvalho de Melo 	/* Should agree with poll, otherwise some programs break */
169c530cfb1SArnaldo Carvalho de Melo 	if (sock_writeable(sk))
170c530cfb1SArnaldo Carvalho de Melo 		sk_wake_async(sk, 2, POLL_OUT);
171c530cfb1SArnaldo Carvalho de Melo 
172c530cfb1SArnaldo Carvalho de Melo 	read_unlock(&sk->sk_callback_lock);
173c530cfb1SArnaldo Carvalho de Melo }
174c530cfb1SArnaldo Carvalho de Melo 
175d6809c12SArnaldo Carvalho de Melo /**
176d6809c12SArnaldo Carvalho de Melo  * dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet
177d6809c12SArnaldo Carvalho de Melo  * @sk: socket to wait for
178d6809c12SArnaldo Carvalho de Melo  */
1795cc3741dSIan McDonald static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb)
180d6809c12SArnaldo Carvalho de Melo {
181d6809c12SArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
182d6809c12SArnaldo Carvalho de Melo 	DEFINE_WAIT(wait);
1835cc3741dSIan McDonald 	unsigned long delay;
184d6809c12SArnaldo Carvalho de Melo 	int rc;
185d6809c12SArnaldo Carvalho de Melo 
186d6809c12SArnaldo Carvalho de Melo 	while (1) {
187d6809c12SArnaldo Carvalho de Melo 		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
188d6809c12SArnaldo Carvalho de Melo 
18997e5848dSIan McDonald 		if (sk->sk_err)
190d6809c12SArnaldo Carvalho de Melo 			goto do_error;
191d6809c12SArnaldo Carvalho de Melo 		if (signal_pending(current))
192d6809c12SArnaldo Carvalho de Melo 			goto do_interrupted;
193d6809c12SArnaldo Carvalho de Melo 
1946b57c93dSGerrit Renker 		rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
195d6809c12SArnaldo Carvalho de Melo 		if (rc <= 0)
196d6809c12SArnaldo Carvalho de Melo 			break;
197d6809c12SArnaldo Carvalho de Melo 		delay = msecs_to_jiffies(rc);
198d6809c12SArnaldo Carvalho de Melo 		sk->sk_write_pending++;
199d6809c12SArnaldo Carvalho de Melo 		release_sock(sk);
2005cc3741dSIan McDonald 		schedule_timeout(delay);
201d6809c12SArnaldo Carvalho de Melo 		lock_sock(sk);
202d6809c12SArnaldo Carvalho de Melo 		sk->sk_write_pending--;
203d6809c12SArnaldo Carvalho de Melo 	}
204d6809c12SArnaldo Carvalho de Melo out:
205d6809c12SArnaldo Carvalho de Melo 	finish_wait(sk->sk_sleep, &wait);
206d6809c12SArnaldo Carvalho de Melo 	return rc;
207d6809c12SArnaldo Carvalho de Melo 
208d6809c12SArnaldo Carvalho de Melo do_error:
209d6809c12SArnaldo Carvalho de Melo 	rc = -EPIPE;
210d6809c12SArnaldo Carvalho de Melo 	goto out;
211d6809c12SArnaldo Carvalho de Melo do_interrupted:
2125cc3741dSIan McDonald 	rc = -EINTR;
213d6809c12SArnaldo Carvalho de Melo 	goto out;
214d6809c12SArnaldo Carvalho de Melo }
215d6809c12SArnaldo Carvalho de Melo 
21697e5848dSIan McDonald static void dccp_write_xmit_timer(unsigned long data) {
21797e5848dSIan McDonald 	struct sock *sk = (struct sock *)data;
21897e5848dSIan McDonald 	struct dccp_sock *dp = dccp_sk(sk);
21997e5848dSIan McDonald 
22097e5848dSIan McDonald 	bh_lock_sock(sk);
22197e5848dSIan McDonald 	if (sock_owned_by_user(sk))
22297e5848dSIan McDonald 		sk_reset_timer(sk, &dp->dccps_xmit_timer, jiffies+1);
22397e5848dSIan McDonald 	else
22497e5848dSIan McDonald 		dccp_write_xmit(sk, 0);
22597e5848dSIan McDonald 	bh_unlock_sock(sk);
22697e5848dSIan McDonald 	sock_put(sk);
22797e5848dSIan McDonald }
22897e5848dSIan McDonald 
22997e5848dSIan McDonald void dccp_write_xmit(struct sock *sk, int block)
23027258ee5SArnaldo Carvalho de Melo {
23197e5848dSIan McDonald 	struct dccp_sock *dp = dccp_sk(sk);
23297e5848dSIan McDonald 	struct sk_buff *skb;
23397e5848dSIan McDonald 
23497e5848dSIan McDonald 	while ((skb = skb_peek(&sk->sk_write_queue))) {
2356b57c93dSGerrit Renker 		int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
236d6809c12SArnaldo Carvalho de Melo 
23797e5848dSIan McDonald 		if (err > 0) {
23897e5848dSIan McDonald 			if (!block) {
23997e5848dSIan McDonald 				sk_reset_timer(sk, &dp->dccps_xmit_timer,
24097e5848dSIan McDonald 						msecs_to_jiffies(err)+jiffies);
24197e5848dSIan McDonald 				break;
2425cc3741dSIan McDonald 			} else
2435cc3741dSIan McDonald 				err = dccp_wait_for_ccid(sk, skb);
24459348b19SGerrit Renker 			if (err)
24559348b19SGerrit Renker 				DCCP_BUG("err=%d after dccp_wait_for_ccid", err);
24697e5848dSIan McDonald 		}
24727258ee5SArnaldo Carvalho de Melo 
24897e5848dSIan McDonald 		skb_dequeue(&sk->sk_write_queue);
24927258ee5SArnaldo Carvalho de Melo 		if (err == 0) {
25027258ee5SArnaldo Carvalho de Melo 			struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
251d6809c12SArnaldo Carvalho de Melo 			const int len = skb->len;
25227258ee5SArnaldo Carvalho de Melo 
25327258ee5SArnaldo Carvalho de Melo 			if (sk->sk_state == DCCP_PARTOPEN) {
25427258ee5SArnaldo Carvalho de Melo 				/* See 8.1.5.  Handshake Completion */
25527258ee5SArnaldo Carvalho de Melo 				inet_csk_schedule_ack(sk);
25627258ee5SArnaldo Carvalho de Melo 				inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
25727258ee5SArnaldo Carvalho de Melo 						  inet_csk(sk)->icsk_rto,
25827258ee5SArnaldo Carvalho de Melo 						  DCCP_RTO_MAX);
25927258ee5SArnaldo Carvalho de Melo 				dcb->dccpd_type = DCCP_PKT_DATAACK;
260ae31c339SArnaldo Carvalho de Melo 			} else if (dccp_ack_pending(sk))
26127258ee5SArnaldo Carvalho de Melo 				dcb->dccpd_type = DCCP_PKT_DATAACK;
26227258ee5SArnaldo Carvalho de Melo 			else
26327258ee5SArnaldo Carvalho de Melo 				dcb->dccpd_type = DCCP_PKT_DATA;
26427258ee5SArnaldo Carvalho de Melo 
26527258ee5SArnaldo Carvalho de Melo 			err = dccp_transmit_skb(sk, skb);
26627258ee5SArnaldo Carvalho de Melo 			ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
26759348b19SGerrit Renker 			if (err)
26859348b19SGerrit Renker 				DCCP_BUG("err=%d after ccid_hc_tx_packet_sent",
26959348b19SGerrit Renker 					 err);
270ffa29347SHerbert Xu 		} else
27197e5848dSIan McDonald 			kfree(skb);
27297e5848dSIan McDonald 	}
27327258ee5SArnaldo Carvalho de Melo }
27427258ee5SArnaldo Carvalho de Melo 
2757c657876SArnaldo Carvalho de Melo int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
2767c657876SArnaldo Carvalho de Melo {
27757cca05aSArnaldo Carvalho de Melo 	if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk) != 0)
2787c657876SArnaldo Carvalho de Melo 		return -EHOSTUNREACH; /* Routing failure or similar. */
2797c657876SArnaldo Carvalho de Melo 
2807c657876SArnaldo Carvalho de Melo 	return dccp_transmit_skb(sk, (skb_cloned(skb) ?
2817c657876SArnaldo Carvalho de Melo 				      pskb_copy(skb, GFP_ATOMIC):
2827c657876SArnaldo Carvalho de Melo 				      skb_clone(skb, GFP_ATOMIC)));
2837c657876SArnaldo Carvalho de Melo }
2847c657876SArnaldo Carvalho de Melo 
2857c657876SArnaldo Carvalho de Melo struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
2867c657876SArnaldo Carvalho de Melo 				   struct request_sock *req)
2877c657876SArnaldo Carvalho de Melo {
2887c657876SArnaldo Carvalho de Melo 	struct dccp_hdr *dh;
28967e6b629SArnaldo Carvalho de Melo 	struct dccp_request_sock *dreq;
290118b2c95SArnaldo Carvalho de Melo 	const u32 dccp_header_size = sizeof(struct dccp_hdr) +
2917c657876SArnaldo Carvalho de Melo 				     sizeof(struct dccp_hdr_ext) +
2927c657876SArnaldo Carvalho de Melo 				     sizeof(struct dccp_hdr_response);
293118b2c95SArnaldo Carvalho de Melo 	struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1,
2947c657876SArnaldo Carvalho de Melo 					   GFP_ATOMIC);
2957c657876SArnaldo Carvalho de Melo 	if (skb == NULL)
2967c657876SArnaldo Carvalho de Melo 		return NULL;
2977c657876SArnaldo Carvalho de Melo 
2987c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers. */
299118b2c95SArnaldo Carvalho de Melo 	skb_reserve(skb, sk->sk_prot->max_header);
3007c657876SArnaldo Carvalho de Melo 
3017c657876SArnaldo Carvalho de Melo 	skb->dst = dst_clone(dst);
3027c657876SArnaldo Carvalho de Melo 
30367e6b629SArnaldo Carvalho de Melo 	dreq = dccp_rsk(req);
304e11d9d30SGerrit Renker 	if (inet_rsk(req)->acked)	/* increase ISS upon retransmission */
305e11d9d30SGerrit Renker 		dccp_inc_seqno(&dreq->dreq_iss);
3067c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
30767e6b629SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
3082d0817d1SArnaldo Carvalho de Melo 
3092d0817d1SArnaldo Carvalho de Melo 	if (dccp_insert_options(sk, skb)) {
3102d0817d1SArnaldo Carvalho de Melo 		kfree_skb(skb);
3112d0817d1SArnaldo Carvalho de Melo 		return NULL;
3122d0817d1SArnaldo Carvalho de Melo 	}
3137c657876SArnaldo Carvalho de Melo 
31409dbc389SGerrit Renker 	/* Build and checksum header */
3159b42078eSGerrit Renker 	dh = dccp_zeroed_hdr(skb, dccp_header_size);
3167c657876SArnaldo Carvalho de Melo 
3177c657876SArnaldo Carvalho de Melo 	dh->dccph_sport	= inet_sk(sk)->sport;
3187c657876SArnaldo Carvalho de Melo 	dh->dccph_dport	= inet_rsk(req)->rmt_port;
3197690af3fSArnaldo Carvalho de Melo 	dh->dccph_doff	= (dccp_header_size +
3207690af3fSArnaldo Carvalho de Melo 			   DCCP_SKB_CB(skb)->dccpd_opt_len) / 4;
3217c657876SArnaldo Carvalho de Melo 	dh->dccph_type	= DCCP_PKT_RESPONSE;
3227c657876SArnaldo Carvalho de Melo 	dh->dccph_x	= 1;
32367e6b629SArnaldo Carvalho de Melo 	dccp_hdr_set_seq(dh, dreq->dreq_iss);
32467e6b629SArnaldo Carvalho de Melo 	dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr);
32567e6b629SArnaldo Carvalho de Melo 	dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service;
3267c657876SArnaldo Carvalho de Melo 
3276f4e5fffSGerrit Renker 	dccp_csum_outgoing(skb);
3286f4e5fffSGerrit Renker 
329e11d9d30SGerrit Renker 	/* We use `acked' to remember that a Response was already sent. */
330e11d9d30SGerrit Renker 	inet_rsk(req)->acked = 1;
3317c657876SArnaldo Carvalho de Melo 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
3327c657876SArnaldo Carvalho de Melo 	return skb;
3337c657876SArnaldo Carvalho de Melo }
3347c657876SArnaldo Carvalho de Melo 
335f21e68caSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_make_response);
336f21e68caSArnaldo Carvalho de Melo 
337017487d7SArnaldo Carvalho de Melo static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
3387c657876SArnaldo Carvalho de Melo 				       const enum dccp_reset_codes code)
3397c657876SArnaldo Carvalho de Melo 
3407c657876SArnaldo Carvalho de Melo {
3417c657876SArnaldo Carvalho de Melo 	struct dccp_hdr *dh;
3427c657876SArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
343118b2c95SArnaldo Carvalho de Melo 	const u32 dccp_header_size = sizeof(struct dccp_hdr) +
3447c657876SArnaldo Carvalho de Melo 				     sizeof(struct dccp_hdr_ext) +
3457c657876SArnaldo Carvalho de Melo 				     sizeof(struct dccp_hdr_reset);
346118b2c95SArnaldo Carvalho de Melo 	struct sk_buff *skb = sock_wmalloc(sk, sk->sk_prot->max_header, 1,
3477c657876SArnaldo Carvalho de Melo 					   GFP_ATOMIC);
3487c657876SArnaldo Carvalho de Melo 	if (skb == NULL)
3497c657876SArnaldo Carvalho de Melo 		return NULL;
3507c657876SArnaldo Carvalho de Melo 
3517c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers. */
352118b2c95SArnaldo Carvalho de Melo 	skb_reserve(skb, sk->sk_prot->max_header);
3537c657876SArnaldo Carvalho de Melo 
3547c657876SArnaldo Carvalho de Melo 	skb->dst = dst_clone(dst);
3557c657876SArnaldo Carvalho de Melo 
3567c657876SArnaldo Carvalho de Melo 	dccp_inc_seqno(&dp->dccps_gss);
3577c657876SArnaldo Carvalho de Melo 
3587c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_reset_code = code;
3597c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type	   = DCCP_PKT_RESET;
3607c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_seq	   = dp->dccps_gss;
3612d0817d1SArnaldo Carvalho de Melo 
3622d0817d1SArnaldo Carvalho de Melo 	if (dccp_insert_options(sk, skb)) {
3632d0817d1SArnaldo Carvalho de Melo 		kfree_skb(skb);
3642d0817d1SArnaldo Carvalho de Melo 		return NULL;
3652d0817d1SArnaldo Carvalho de Melo 	}
3667c657876SArnaldo Carvalho de Melo 
3679b42078eSGerrit Renker 	dh = dccp_zeroed_hdr(skb, dccp_header_size);
3687c657876SArnaldo Carvalho de Melo 
3697c657876SArnaldo Carvalho de Melo 	dh->dccph_sport	= inet_sk(sk)->sport;
3707c657876SArnaldo Carvalho de Melo 	dh->dccph_dport	= inet_sk(sk)->dport;
3717690af3fSArnaldo Carvalho de Melo 	dh->dccph_doff	= (dccp_header_size +
3727690af3fSArnaldo Carvalho de Melo 			   DCCP_SKB_CB(skb)->dccpd_opt_len) / 4;
3737c657876SArnaldo Carvalho de Melo 	dh->dccph_type	= DCCP_PKT_RESET;
3747c657876SArnaldo Carvalho de Melo 	dh->dccph_x	= 1;
3757c657876SArnaldo Carvalho de Melo 	dccp_hdr_set_seq(dh, dp->dccps_gss);
3767c657876SArnaldo Carvalho de Melo 	dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr);
3777c657876SArnaldo Carvalho de Melo 
3787c657876SArnaldo Carvalho de Melo 	dccp_hdr_reset(skb)->dccph_reset_code = code;
3796f4e5fffSGerrit Renker 	inet_csk(sk)->icsk_af_ops->send_check(sk, 0, skb);
3807c657876SArnaldo Carvalho de Melo 
3817c657876SArnaldo Carvalho de Melo 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
3827c657876SArnaldo Carvalho de Melo 	return skb;
3837c657876SArnaldo Carvalho de Melo }
3847c657876SArnaldo Carvalho de Melo 
385017487d7SArnaldo Carvalho de Melo int dccp_send_reset(struct sock *sk, enum dccp_reset_codes code)
386017487d7SArnaldo Carvalho de Melo {
387017487d7SArnaldo Carvalho de Melo 	/*
388017487d7SArnaldo Carvalho de Melo 	 * FIXME: what if rebuild_header fails?
389017487d7SArnaldo Carvalho de Melo 	 * Should we be doing a rebuild_header here?
390017487d7SArnaldo Carvalho de Melo 	 */
391017487d7SArnaldo Carvalho de Melo 	int err = inet_sk_rebuild_header(sk);
392017487d7SArnaldo Carvalho de Melo 
393017487d7SArnaldo Carvalho de Melo 	if (err == 0) {
394017487d7SArnaldo Carvalho de Melo 		struct sk_buff *skb = dccp_make_reset(sk, sk->sk_dst_cache,
395017487d7SArnaldo Carvalho de Melo 						      code);
396017487d7SArnaldo Carvalho de Melo 		if (skb != NULL) {
397017487d7SArnaldo Carvalho de Melo 			memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
39893173112SDavid S. Miller 			err = inet_csk(sk)->icsk_af_ops->queue_xmit(skb, sk, 0);
399b9df3cb8SGerrit Renker 			return net_xmit_eval(err);
400017487d7SArnaldo Carvalho de Melo 		}
401017487d7SArnaldo Carvalho de Melo 	}
402017487d7SArnaldo Carvalho de Melo 
403017487d7SArnaldo Carvalho de Melo 	return err;
404017487d7SArnaldo Carvalho de Melo }
405017487d7SArnaldo Carvalho de Melo 
4067c657876SArnaldo Carvalho de Melo /*
4077c657876SArnaldo Carvalho de Melo  * Do all connect socket setups that can be done AF independent.
4087c657876SArnaldo Carvalho de Melo  */
4097c657876SArnaldo Carvalho de Melo static inline void dccp_connect_init(struct sock *sk)
4107c657876SArnaldo Carvalho de Melo {
411f21e68caSArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
4127c657876SArnaldo Carvalho de Melo 	struct dst_entry *dst = __sk_dst_get(sk);
4137c657876SArnaldo Carvalho de Melo 	struct inet_connection_sock *icsk = inet_csk(sk);
4147c657876SArnaldo Carvalho de Melo 
4157c657876SArnaldo Carvalho de Melo 	sk->sk_err = 0;
4167c657876SArnaldo Carvalho de Melo 	sock_reset_flag(sk, SOCK_DONE);
4177c657876SArnaldo Carvalho de Melo 
4187c657876SArnaldo Carvalho de Melo 	dccp_sync_mss(sk, dst_mtu(dst));
4197c657876SArnaldo Carvalho de Melo 
4207c657876SArnaldo Carvalho de Melo  	/*
421f21e68caSArnaldo Carvalho de Melo 	 * SWL and AWL are initially adjusted so that they are not less than
422f21e68caSArnaldo Carvalho de Melo 	 * the initial Sequence Numbers received and sent, respectively:
423f21e68caSArnaldo Carvalho de Melo 	 *	SWL := max(GSR + 1 - floor(W/4), ISR),
424f21e68caSArnaldo Carvalho de Melo 	 *	AWL := max(GSS - W' + 1, ISS).
425f21e68caSArnaldo Carvalho de Melo 	 * These adjustments MUST be applied only at the beginning of the
426f21e68caSArnaldo Carvalho de Melo 	 * connection.
4277c657876SArnaldo Carvalho de Melo  	 */
428d7f7365fSGerrit Renker 	dccp_update_gss(sk, dp->dccps_iss);
429f21e68caSArnaldo Carvalho de Melo 	dccp_set_seqno(&dp->dccps_awl, max48(dp->dccps_awl, dp->dccps_iss));
4307c657876SArnaldo Carvalho de Melo 
431d7f7365fSGerrit Renker 	/* S.GAR - greatest valid acknowledgement number received on a non-Sync;
432d7f7365fSGerrit Renker 	 *         initialized to S.ISS (sec. 8.5)                            */
433d7f7365fSGerrit Renker 	dp->dccps_gar = dp->dccps_iss;
434d7f7365fSGerrit Renker 
4357c657876SArnaldo Carvalho de Melo 	icsk->icsk_retransmits = 0;
43697e5848dSIan McDonald 	init_timer(&dp->dccps_xmit_timer);
43797e5848dSIan McDonald 	dp->dccps_xmit_timer.data = (unsigned long)sk;
43897e5848dSIan McDonald 	dp->dccps_xmit_timer.function = dccp_write_xmit_timer;
4397c657876SArnaldo Carvalho de Melo }
4407c657876SArnaldo Carvalho de Melo 
4417c657876SArnaldo Carvalho de Melo int dccp_connect(struct sock *sk)
4427c657876SArnaldo Carvalho de Melo {
4437c657876SArnaldo Carvalho de Melo 	struct sk_buff *skb;
4447c657876SArnaldo Carvalho de Melo 	struct inet_connection_sock *icsk = inet_csk(sk);
4457c657876SArnaldo Carvalho de Melo 
4467c657876SArnaldo Carvalho de Melo 	dccp_connect_init(sk);
4477c657876SArnaldo Carvalho de Melo 
448118b2c95SArnaldo Carvalho de Melo 	skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation);
4497c657876SArnaldo Carvalho de Melo 	if (unlikely(skb == NULL))
4507c657876SArnaldo Carvalho de Melo 		return -ENOBUFS;
4517c657876SArnaldo Carvalho de Melo 
4527c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers. */
453118b2c95SArnaldo Carvalho de Melo 	skb_reserve(skb, sk->sk_prot->max_header);
4547c657876SArnaldo Carvalho de Melo 
4557c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST;
4567c657876SArnaldo Carvalho de Melo 
45748918a4dSHerbert Xu 	dccp_skb_entail(sk, skb);
4587c657876SArnaldo Carvalho de Melo 	dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL));
4597c657876SArnaldo Carvalho de Melo 	DCCP_INC_STATS(DCCP_MIB_ACTIVEOPENS);
4607c657876SArnaldo Carvalho de Melo 
4617c657876SArnaldo Carvalho de Melo 	/* Timer for repeating the REQUEST until an answer. */
46227258ee5SArnaldo Carvalho de Melo 	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
46327258ee5SArnaldo Carvalho de Melo 				  icsk->icsk_rto, DCCP_RTO_MAX);
4647c657876SArnaldo Carvalho de Melo 	return 0;
4657c657876SArnaldo Carvalho de Melo }
4667c657876SArnaldo Carvalho de Melo 
467f21e68caSArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_connect);
468f21e68caSArnaldo Carvalho de Melo 
4697c657876SArnaldo Carvalho de Melo void dccp_send_ack(struct sock *sk)
4707c657876SArnaldo Carvalho de Melo {
4717c657876SArnaldo Carvalho de Melo 	/* If we have been reset, we may not send again. */
4727c657876SArnaldo Carvalho de Melo 	if (sk->sk_state != DCCP_CLOSED) {
473118b2c95SArnaldo Carvalho de Melo 		struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header,
474118b2c95SArnaldo Carvalho de Melo 						GFP_ATOMIC);
4757c657876SArnaldo Carvalho de Melo 
4767c657876SArnaldo Carvalho de Melo 		if (skb == NULL) {
4777c657876SArnaldo Carvalho de Melo 			inet_csk_schedule_ack(sk);
4787c657876SArnaldo Carvalho de Melo 			inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN;
4797690af3fSArnaldo Carvalho de Melo 			inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
4807690af3fSArnaldo Carvalho de Melo 						  TCP_DELACK_MAX,
4817690af3fSArnaldo Carvalho de Melo 						  DCCP_RTO_MAX);
4827c657876SArnaldo Carvalho de Melo 			return;
4837c657876SArnaldo Carvalho de Melo 		}
4847c657876SArnaldo Carvalho de Melo 
4857c657876SArnaldo Carvalho de Melo 		/* Reserve space for headers */
486118b2c95SArnaldo Carvalho de Melo 		skb_reserve(skb, sk->sk_prot->max_header);
4877c657876SArnaldo Carvalho de Melo 		DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK;
4887c657876SArnaldo Carvalho de Melo 		dccp_transmit_skb(sk, skb);
4897c657876SArnaldo Carvalho de Melo 	}
4907c657876SArnaldo Carvalho de Melo }
4917c657876SArnaldo Carvalho de Melo 
4927c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_send_ack);
4937c657876SArnaldo Carvalho de Melo 
4947c657876SArnaldo Carvalho de Melo void dccp_send_delayed_ack(struct sock *sk)
4957c657876SArnaldo Carvalho de Melo {
4967c657876SArnaldo Carvalho de Melo 	struct inet_connection_sock *icsk = inet_csk(sk);
4977c657876SArnaldo Carvalho de Melo 	/*
4987c657876SArnaldo Carvalho de Melo 	 * FIXME: tune this timer. elapsed time fixes the skew, so no problem
4997c657876SArnaldo Carvalho de Melo 	 * with using 2s, and active senders also piggyback the ACK into a
5007c657876SArnaldo Carvalho de Melo 	 * DATAACK packet, so this is really for quiescent senders.
5017c657876SArnaldo Carvalho de Melo 	 */
5027c657876SArnaldo Carvalho de Melo 	unsigned long timeout = jiffies + 2 * HZ;
5037c657876SArnaldo Carvalho de Melo 
5047c657876SArnaldo Carvalho de Melo 	/* Use new timeout only if there wasn't a older one earlier. */
5057c657876SArnaldo Carvalho de Melo 	if (icsk->icsk_ack.pending & ICSK_ACK_TIMER) {
5067c657876SArnaldo Carvalho de Melo 		/* If delack timer was blocked or is about to expire,
5077c657876SArnaldo Carvalho de Melo 		 * send ACK now.
5087c657876SArnaldo Carvalho de Melo 		 *
5097c657876SArnaldo Carvalho de Melo 		 * FIXME: check the "about to expire" part
5107c657876SArnaldo Carvalho de Melo 		 */
5117c657876SArnaldo Carvalho de Melo 		if (icsk->icsk_ack.blocked) {
5127c657876SArnaldo Carvalho de Melo 			dccp_send_ack(sk);
5137c657876SArnaldo Carvalho de Melo 			return;
5147c657876SArnaldo Carvalho de Melo 		}
5157c657876SArnaldo Carvalho de Melo 
5167c657876SArnaldo Carvalho de Melo 		if (!time_before(timeout, icsk->icsk_ack.timeout))
5177c657876SArnaldo Carvalho de Melo 			timeout = icsk->icsk_ack.timeout;
5187c657876SArnaldo Carvalho de Melo 	}
5197c657876SArnaldo Carvalho de Melo 	icsk->icsk_ack.pending |= ICSK_ACK_SCHED | ICSK_ACK_TIMER;
5207c657876SArnaldo Carvalho de Melo 	icsk->icsk_ack.timeout = timeout;
5217c657876SArnaldo Carvalho de Melo 	sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout);
5227c657876SArnaldo Carvalho de Melo }
5237c657876SArnaldo Carvalho de Melo 
524e92ae93aSArnaldo Carvalho de Melo void dccp_send_sync(struct sock *sk, const u64 seq,
525e92ae93aSArnaldo Carvalho de Melo 		    const enum dccp_pkt_type pkt_type)
5267c657876SArnaldo Carvalho de Melo {
5277c657876SArnaldo Carvalho de Melo 	/*
5287c657876SArnaldo Carvalho de Melo 	 * We are not putting this on the write queue, so
5297c657876SArnaldo Carvalho de Melo 	 * dccp_transmit_skb() will set the ownership to this
5307c657876SArnaldo Carvalho de Melo 	 * sock.
5317c657876SArnaldo Carvalho de Melo 	 */
532118b2c95SArnaldo Carvalho de Melo 	struct sk_buff *skb = alloc_skb(sk->sk_prot->max_header, GFP_ATOMIC);
5337c657876SArnaldo Carvalho de Melo 
5347c657876SArnaldo Carvalho de Melo 	if (skb == NULL)
5357c657876SArnaldo Carvalho de Melo 		/* FIXME: how to make sure the sync is sent? */
5367c657876SArnaldo Carvalho de Melo 		return;
5377c657876SArnaldo Carvalho de Melo 
5387c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers and prepare control bits. */
539118b2c95SArnaldo Carvalho de Melo 	skb_reserve(skb, sk->sk_prot->max_header);
540e92ae93aSArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type = pkt_type;
5417c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_seq = seq;
5427c657876SArnaldo Carvalho de Melo 
5437c657876SArnaldo Carvalho de Melo 	dccp_transmit_skb(sk, skb);
5447c657876SArnaldo Carvalho de Melo }
5457c657876SArnaldo Carvalho de Melo 
546b61fafc4SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_send_sync);
547b61fafc4SArnaldo Carvalho de Melo 
5487690af3fSArnaldo Carvalho de Melo /*
5497690af3fSArnaldo Carvalho de Melo  * Send a DCCP_PKT_CLOSE/CLOSEREQ. The caller locks the socket for us. This
5507690af3fSArnaldo Carvalho de Melo  * cannot be allowed to fail queueing a DCCP_PKT_CLOSE/CLOSEREQ frame under
5517690af3fSArnaldo Carvalho de Melo  * any circumstances.
5527c657876SArnaldo Carvalho de Melo  */
5537ad07e7cSArnaldo Carvalho de Melo void dccp_send_close(struct sock *sk, const int active)
5547c657876SArnaldo Carvalho de Melo {
5557c657876SArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
5567c657876SArnaldo Carvalho de Melo 	struct sk_buff *skb;
5577d877f3bSAl Viro 	const gfp_t prio = active ? GFP_KERNEL : GFP_ATOMIC;
5587c657876SArnaldo Carvalho de Melo 
5597ad07e7cSArnaldo Carvalho de Melo 	skb = alloc_skb(sk->sk_prot->max_header, prio);
5607ad07e7cSArnaldo Carvalho de Melo 	if (skb == NULL)
5617ad07e7cSArnaldo Carvalho de Melo 		return;
5627c657876SArnaldo Carvalho de Melo 
5637c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers and prepare control bits. */
5647c657876SArnaldo Carvalho de Melo 	skb_reserve(skb, sk->sk_prot->max_header);
5657690af3fSArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ?
5667690af3fSArnaldo Carvalho de Melo 					DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ;
5677c657876SArnaldo Carvalho de Melo 
5687ad07e7cSArnaldo Carvalho de Melo 	if (active) {
56997e5848dSIan McDonald 		dccp_write_xmit(sk, 1);
57048918a4dSHerbert Xu 		dccp_skb_entail(sk, skb);
5717ad07e7cSArnaldo Carvalho de Melo 		dccp_transmit_skb(sk, skb_clone(skb, prio));
57297e5848dSIan McDonald 		/* FIXME do we need a retransmit timer here? */
5737ad07e7cSArnaldo Carvalho de Melo 	} else
5747c657876SArnaldo Carvalho de Melo 		dccp_transmit_skb(sk, skb);
5757c657876SArnaldo Carvalho de Melo }
576