xref: /openbmc/linux/net/dccp/output.c (revision edc9e819)
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/config.h>
147c657876SArnaldo Carvalho de Melo #include <linux/dccp.h>
1548918a4dSHerbert Xu #include <linux/kernel.h>
167c657876SArnaldo Carvalho de Melo #include <linux/skbuff.h>
177c657876SArnaldo Carvalho de Melo 
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 
2948918a4dSHerbert Xu static inline 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);
467c657876SArnaldo Carvalho de Melo 		struct dccp_sock *dp = dccp_sk(sk);
477c657876SArnaldo Carvalho de Melo 		struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
487c657876SArnaldo Carvalho de Melo 		struct dccp_hdr *dh;
497c657876SArnaldo Carvalho de Melo 		/* XXX For now we're using only 48 bits sequence numbers */
507c657876SArnaldo Carvalho de Melo 		const int dccp_header_size = sizeof(*dh) +
517c657876SArnaldo Carvalho de Melo 					     sizeof(struct dccp_hdr_ext) +
527c657876SArnaldo Carvalho de Melo 					  dccp_packet_hdr_len(dcb->dccpd_type);
537c657876SArnaldo Carvalho de Melo 		int err, set_ack = 1;
547c657876SArnaldo Carvalho de Melo 		u64 ackno = dp->dccps_gsr;
557c657876SArnaldo Carvalho de Melo 
567c657876SArnaldo Carvalho de Melo 		dccp_inc_seqno(&dp->dccps_gss);
577c657876SArnaldo Carvalho de Melo 
587c657876SArnaldo Carvalho de Melo 		switch (dcb->dccpd_type) {
597c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_DATA:
607c657876SArnaldo Carvalho de Melo 			set_ack = 0;
61edc9e819SHerbert Xu 			/* fall through */
62edc9e819SHerbert Xu 		case DCCP_PKT_DATAACK:
637c657876SArnaldo Carvalho de Melo 			break;
64edc9e819SHerbert Xu 
657c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_SYNC:
667c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_SYNCACK:
677c657876SArnaldo Carvalho de Melo 			ackno = dcb->dccpd_seq;
68edc9e819SHerbert Xu 			/* fall through */
69edc9e819SHerbert Xu 		default:
70edc9e819SHerbert Xu 			/*
71edc9e819SHerbert Xu 			 * Only data packets should come through with skb->sk
72edc9e819SHerbert Xu 			 * set.
73edc9e819SHerbert Xu 			 */
74edc9e819SHerbert Xu 			WARN_ON(skb->sk);
75edc9e819SHerbert Xu 			skb_set_owner_w(skb, sk);
767c657876SArnaldo Carvalho de Melo 			break;
777c657876SArnaldo Carvalho de Melo 		}
787c657876SArnaldo Carvalho de Melo 
7924117727SArnaldo Carvalho de Melo 		dcb->dccpd_seq = dp->dccps_gss;
8024117727SArnaldo Carvalho de Melo 		dccp_insert_options(sk, skb);
8124117727SArnaldo Carvalho de Melo 
827c657876SArnaldo Carvalho de Melo 		skb->h.raw = skb_push(skb, dccp_header_size);
837c657876SArnaldo Carvalho de Melo 		dh = dccp_hdr(skb);
84fda0fd6cSHerbert Xu 
857c657876SArnaldo Carvalho de Melo 		/* Build DCCP header and checksum it. */
867c657876SArnaldo Carvalho de Melo 		memset(dh, 0, dccp_header_size);
877c657876SArnaldo Carvalho de Melo 		dh->dccph_type	= dcb->dccpd_type;
887c657876SArnaldo Carvalho de Melo 		dh->dccph_sport	= inet->sport;
897c657876SArnaldo Carvalho de Melo 		dh->dccph_dport	= inet->dport;
907c657876SArnaldo Carvalho de Melo 		dh->dccph_doff	= (dccp_header_size + dcb->dccpd_opt_len) / 4;
917c657876SArnaldo Carvalho de Melo 		dh->dccph_ccval	= dcb->dccpd_ccval;
927c657876SArnaldo Carvalho de Melo 		/* XXX For now we're using only 48 bits sequence numbers */
937c657876SArnaldo Carvalho de Melo 		dh->dccph_x	= 1;
947c657876SArnaldo Carvalho de Melo 
957c657876SArnaldo Carvalho de Melo 		dp->dccps_awh = dp->dccps_gss;
967c657876SArnaldo Carvalho de Melo 		dccp_hdr_set_seq(dh, dp->dccps_gss);
977c657876SArnaldo Carvalho de Melo 		if (set_ack)
987c657876SArnaldo Carvalho de Melo 			dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), ackno);
997c657876SArnaldo Carvalho de Melo 
1007c657876SArnaldo Carvalho de Melo 		switch (dcb->dccpd_type) {
1017c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_REQUEST:
1027690af3fSArnaldo Carvalho de Melo 			dccp_hdr_request(skb)->dccph_req_service =
10367e6b629SArnaldo Carvalho de Melo 							dp->dccps_service;
1047c657876SArnaldo Carvalho de Melo 			break;
1057c657876SArnaldo Carvalho de Melo 		case DCCP_PKT_RESET:
1067690af3fSArnaldo Carvalho de Melo 			dccp_hdr_reset(skb)->dccph_reset_code =
1077690af3fSArnaldo Carvalho de Melo 							dcb->dccpd_reset_code;
1087c657876SArnaldo Carvalho de Melo 			break;
1097c657876SArnaldo Carvalho de Melo 		}
1107c657876SArnaldo Carvalho de Melo 
11195b81ef7SYoshifumi Nishida 		dh->dccph_checksum = dccp_v4_checksum(skb, inet->saddr,
11295b81ef7SYoshifumi Nishida 						      inet->daddr);
1137c657876SArnaldo Carvalho de Melo 
1147ad07e7cSArnaldo Carvalho de Melo 		if (set_ack)
1157c657876SArnaldo Carvalho de Melo 			dccp_event_ack_sent(sk);
1167c657876SArnaldo Carvalho de Melo 
1177c657876SArnaldo Carvalho de Melo 		DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
1187c657876SArnaldo Carvalho de Melo 
11949c5bfafSHerbert Xu 		memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt));
1207c657876SArnaldo Carvalho de Melo 		err = ip_queue_xmit(skb, 0);
1217c657876SArnaldo Carvalho de Melo 		if (err <= 0)
1227c657876SArnaldo Carvalho de Melo 			return err;
1237c657876SArnaldo Carvalho de Melo 
1247c657876SArnaldo Carvalho de Melo 		/* NET_XMIT_CN is special. It does not guarantee,
1257c657876SArnaldo Carvalho de Melo 		 * that this packet is lost. It tells that device
1267c657876SArnaldo Carvalho de Melo 		 * is about to start to drop packets or already
1277c657876SArnaldo Carvalho de Melo 		 * drops some packets of the same priority and
1287c657876SArnaldo Carvalho de Melo 		 * invokes us to send less aggressively.
1297c657876SArnaldo Carvalho de Melo 		 */
1307c657876SArnaldo Carvalho de Melo 		return err == NET_XMIT_CN ? 0 : err;
1317c657876SArnaldo Carvalho de Melo 	}
1327c657876SArnaldo Carvalho de Melo 	return -ENOBUFS;
1337c657876SArnaldo Carvalho de Melo }
1347c657876SArnaldo Carvalho de Melo 
1357c657876SArnaldo Carvalho de Melo unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu)
1367c657876SArnaldo Carvalho de Melo {
1377c657876SArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
1387c657876SArnaldo Carvalho de Melo 	int mss_now;
1397c657876SArnaldo Carvalho de Melo 
1407c657876SArnaldo Carvalho de Melo 	/*
1417690af3fSArnaldo Carvalho de Melo 	 * FIXME: we really should be using the af_specific thing to support
1427690af3fSArnaldo Carvalho de Melo 	 * 	  IPv6.
1437690af3fSArnaldo Carvalho de Melo 	 * mss_now = pmtu - tp->af_specific->net_header_len -
1447690af3fSArnaldo Carvalho de Melo 	 * 	     sizeof(struct dccp_hdr) - sizeof(struct dccp_hdr_ext);
1457c657876SArnaldo Carvalho de Melo 	 */
1467690af3fSArnaldo Carvalho de Melo 	mss_now = pmtu - sizeof(struct iphdr) - sizeof(struct dccp_hdr) -
1477690af3fSArnaldo Carvalho de Melo 		  sizeof(struct dccp_hdr_ext);
1487c657876SArnaldo Carvalho de Melo 
1497c657876SArnaldo Carvalho de Melo 	/* Now subtract optional transport overhead */
1507c657876SArnaldo Carvalho de Melo 	mss_now -= dp->dccps_ext_header_len;
1517c657876SArnaldo Carvalho de Melo 
1527c657876SArnaldo Carvalho de Melo 	/*
1537c657876SArnaldo Carvalho de Melo 	 * FIXME: this should come from the CCID infrastructure, where, say,
1547c657876SArnaldo Carvalho de Melo 	 * TFRC will say it wants TIMESTAMPS, ELAPSED time, etc, for now lets
1557c657876SArnaldo Carvalho de Melo 	 * put a rough estimate for NDP + TIMESTAMP + TIMESTAMP_ECHO + ELAPSED
1567c657876SArnaldo Carvalho de Melo 	 * TIME + TFRC_OPT_LOSS_EVENT_RATE + TFRC_OPT_RECEIVE_RATE + padding to
1577c657876SArnaldo Carvalho de Melo 	 * make it a multiple of 4
1587c657876SArnaldo Carvalho de Melo 	 */
1597c657876SArnaldo Carvalho de Melo 
1607c657876SArnaldo Carvalho de Melo 	mss_now -= ((5 + 6 + 10 + 6 + 6 + 6 + 3) / 4) * 4;
1617c657876SArnaldo Carvalho de Melo 
1627c657876SArnaldo Carvalho de Melo 	/* And store cached results */
1637c657876SArnaldo Carvalho de Melo 	dp->dccps_pmtu_cookie = pmtu;
1647c657876SArnaldo Carvalho de Melo 	dp->dccps_mss_cache = mss_now;
1657c657876SArnaldo Carvalho de Melo 
1667c657876SArnaldo Carvalho de Melo 	return mss_now;
1677c657876SArnaldo Carvalho de Melo }
1687c657876SArnaldo Carvalho de Melo 
169c530cfb1SArnaldo Carvalho de Melo void dccp_write_space(struct sock *sk)
170c530cfb1SArnaldo Carvalho de Melo {
171c530cfb1SArnaldo Carvalho de Melo 	read_lock(&sk->sk_callback_lock);
172c530cfb1SArnaldo Carvalho de Melo 
173c530cfb1SArnaldo Carvalho de Melo 	if (sk->sk_sleep && waitqueue_active(sk->sk_sleep))
174c530cfb1SArnaldo Carvalho de Melo 		wake_up_interruptible(sk->sk_sleep);
175c530cfb1SArnaldo Carvalho de Melo 	/* Should agree with poll, otherwise some programs break */
176c530cfb1SArnaldo Carvalho de Melo 	if (sock_writeable(sk))
177c530cfb1SArnaldo Carvalho de Melo 		sk_wake_async(sk, 2, POLL_OUT);
178c530cfb1SArnaldo Carvalho de Melo 
179c530cfb1SArnaldo Carvalho de Melo 	read_unlock(&sk->sk_callback_lock);
180c530cfb1SArnaldo Carvalho de Melo }
181c530cfb1SArnaldo Carvalho de Melo 
182d6809c12SArnaldo Carvalho de Melo /**
183d6809c12SArnaldo Carvalho de Melo  * dccp_wait_for_ccid - Wait for ccid to tell us we can send a packet
184d6809c12SArnaldo Carvalho de Melo  * @sk: socket to wait for
185d6809c12SArnaldo Carvalho de Melo  * @timeo: for how long
186d6809c12SArnaldo Carvalho de Melo  */
187d6809c12SArnaldo Carvalho de Melo static int dccp_wait_for_ccid(struct sock *sk, struct sk_buff *skb,
188d6809c12SArnaldo Carvalho de Melo 			      long *timeo)
189d6809c12SArnaldo Carvalho de Melo {
190d6809c12SArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
191d6809c12SArnaldo Carvalho de Melo 	DEFINE_WAIT(wait);
192d6809c12SArnaldo Carvalho de Melo 	long delay;
193d6809c12SArnaldo Carvalho de Melo 	int rc;
194d6809c12SArnaldo Carvalho de Melo 
195d6809c12SArnaldo Carvalho de Melo 	while (1) {
196d6809c12SArnaldo Carvalho de Melo 		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
197d6809c12SArnaldo Carvalho de Melo 
198d6809c12SArnaldo Carvalho de Melo 		if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
199d6809c12SArnaldo Carvalho de Melo 			goto do_error;
200d6809c12SArnaldo Carvalho de Melo 		if (!*timeo)
201d6809c12SArnaldo Carvalho de Melo 			goto do_nonblock;
202d6809c12SArnaldo Carvalho de Melo 		if (signal_pending(current))
203d6809c12SArnaldo Carvalho de Melo 			goto do_interrupted;
204d6809c12SArnaldo Carvalho de Melo 
205d6809c12SArnaldo Carvalho de Melo 		rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
206d6809c12SArnaldo Carvalho de Melo 					    skb->len);
207d6809c12SArnaldo Carvalho de Melo 		if (rc <= 0)
208d6809c12SArnaldo Carvalho de Melo 			break;
209d6809c12SArnaldo Carvalho de Melo 		delay = msecs_to_jiffies(rc);
210d6809c12SArnaldo Carvalho de Melo 		if (delay > *timeo || delay < 0)
211d6809c12SArnaldo Carvalho de Melo 			goto do_nonblock;
212d6809c12SArnaldo Carvalho de Melo 
213d6809c12SArnaldo Carvalho de Melo 		sk->sk_write_pending++;
214d6809c12SArnaldo Carvalho de Melo 		release_sock(sk);
215d6809c12SArnaldo Carvalho de Melo 		*timeo -= schedule_timeout(delay);
216d6809c12SArnaldo Carvalho de Melo 		lock_sock(sk);
217d6809c12SArnaldo Carvalho de Melo 		sk->sk_write_pending--;
218d6809c12SArnaldo Carvalho de Melo 	}
219d6809c12SArnaldo Carvalho de Melo out:
220d6809c12SArnaldo Carvalho de Melo 	finish_wait(sk->sk_sleep, &wait);
221d6809c12SArnaldo Carvalho de Melo 	return rc;
222d6809c12SArnaldo Carvalho de Melo 
223d6809c12SArnaldo Carvalho de Melo do_error:
224d6809c12SArnaldo Carvalho de Melo 	rc = -EPIPE;
225d6809c12SArnaldo Carvalho de Melo 	goto out;
226d6809c12SArnaldo Carvalho de Melo do_nonblock:
227d6809c12SArnaldo Carvalho de Melo 	rc = -EAGAIN;
228d6809c12SArnaldo Carvalho de Melo 	goto out;
229d6809c12SArnaldo Carvalho de Melo do_interrupted:
230d6809c12SArnaldo Carvalho de Melo 	rc = sock_intr_errno(*timeo);
231d6809c12SArnaldo Carvalho de Melo 	goto out;
232d6809c12SArnaldo Carvalho de Melo }
233d6809c12SArnaldo Carvalho de Melo 
234d6809c12SArnaldo Carvalho de Melo int dccp_write_xmit(struct sock *sk, struct sk_buff *skb, long *timeo)
23527258ee5SArnaldo Carvalho de Melo {
23627258ee5SArnaldo Carvalho de Melo 	const struct dccp_sock *dp = dccp_sk(sk);
237d6809c12SArnaldo Carvalho de Melo 	int err = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb,
238d6809c12SArnaldo Carvalho de Melo 					 skb->len);
239d6809c12SArnaldo Carvalho de Melo 
240d6809c12SArnaldo Carvalho de Melo 	if (err > 0)
241d6809c12SArnaldo Carvalho de Melo 		err = dccp_wait_for_ccid(sk, skb, timeo);
24227258ee5SArnaldo Carvalho de Melo 
24327258ee5SArnaldo Carvalho de Melo 	if (err == 0) {
24427258ee5SArnaldo Carvalho de Melo 		struct dccp_skb_cb *dcb = DCCP_SKB_CB(skb);
245d6809c12SArnaldo Carvalho de Melo 		const int len = skb->len;
24627258ee5SArnaldo Carvalho de Melo 
24727258ee5SArnaldo Carvalho de Melo 		if (sk->sk_state == DCCP_PARTOPEN) {
24827258ee5SArnaldo Carvalho de Melo 			/* See 8.1.5.  Handshake Completion */
24927258ee5SArnaldo Carvalho de Melo 			inet_csk_schedule_ack(sk);
25027258ee5SArnaldo Carvalho de Melo 			inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
25127258ee5SArnaldo Carvalho de Melo 						  inet_csk(sk)->icsk_rto,
25227258ee5SArnaldo Carvalho de Melo 						  DCCP_RTO_MAX);
25327258ee5SArnaldo Carvalho de Melo 			dcb->dccpd_type = DCCP_PKT_DATAACK;
254ae31c339SArnaldo Carvalho de Melo 		} else if (dccp_ack_pending(sk))
25527258ee5SArnaldo Carvalho de Melo 			dcb->dccpd_type = DCCP_PKT_DATAACK;
25627258ee5SArnaldo Carvalho de Melo 		else
25727258ee5SArnaldo Carvalho de Melo 			dcb->dccpd_type = DCCP_PKT_DATA;
25827258ee5SArnaldo Carvalho de Melo 
25927258ee5SArnaldo Carvalho de Melo 		err = dccp_transmit_skb(sk, skb);
26027258ee5SArnaldo Carvalho de Melo 		ccid_hc_tx_packet_sent(dp->dccps_hc_tx_ccid, sk, 0, len);
261ffa29347SHerbert Xu 	} else
262ffa29347SHerbert Xu 		kfree_skb(skb);
26327258ee5SArnaldo Carvalho de Melo 
26427258ee5SArnaldo Carvalho de Melo 	return err;
26527258ee5SArnaldo Carvalho de Melo }
26627258ee5SArnaldo Carvalho de Melo 
2677c657876SArnaldo Carvalho de Melo int dccp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
2687c657876SArnaldo Carvalho de Melo {
2697c657876SArnaldo Carvalho de Melo 	if (inet_sk_rebuild_header(sk) != 0)
2707c657876SArnaldo Carvalho de Melo 		return -EHOSTUNREACH; /* Routing failure or similar. */
2717c657876SArnaldo Carvalho de Melo 
2727c657876SArnaldo Carvalho de Melo 	return dccp_transmit_skb(sk, (skb_cloned(skb) ?
2737c657876SArnaldo Carvalho de Melo 				      pskb_copy(skb, GFP_ATOMIC):
2747c657876SArnaldo Carvalho de Melo 				      skb_clone(skb, GFP_ATOMIC)));
2757c657876SArnaldo Carvalho de Melo }
2767c657876SArnaldo Carvalho de Melo 
2777c657876SArnaldo Carvalho de Melo struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
2787c657876SArnaldo Carvalho de Melo 				   struct request_sock *req)
2797c657876SArnaldo Carvalho de Melo {
2807c657876SArnaldo Carvalho de Melo 	struct dccp_hdr *dh;
28167e6b629SArnaldo Carvalho de Melo 	struct dccp_request_sock *dreq;
2827c657876SArnaldo Carvalho de Melo 	const int dccp_header_size = sizeof(struct dccp_hdr) +
2837c657876SArnaldo Carvalho de Melo 				     sizeof(struct dccp_hdr_ext) +
2847c657876SArnaldo Carvalho de Melo 				     sizeof(struct dccp_hdr_response);
2857c657876SArnaldo Carvalho de Melo 	struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN +
2867c657876SArnaldo Carvalho de Melo 					       dccp_header_size, 1,
2877c657876SArnaldo Carvalho de Melo 					   GFP_ATOMIC);
2887c657876SArnaldo Carvalho de Melo 	if (skb == NULL)
2897c657876SArnaldo Carvalho de Melo 		return NULL;
2907c657876SArnaldo Carvalho de Melo 
2917c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers. */
2927c657876SArnaldo Carvalho de Melo 	skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size);
2937c657876SArnaldo Carvalho de Melo 
2947c657876SArnaldo Carvalho de Melo 	skb->dst = dst_clone(dst);
2957c657876SArnaldo Carvalho de Melo 	skb->csum = 0;
2967c657876SArnaldo Carvalho de Melo 
29767e6b629SArnaldo Carvalho de Melo 	dreq = dccp_rsk(req);
2987c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
29967e6b629SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_seq  = dreq->dreq_iss;
3007c657876SArnaldo Carvalho de Melo 	dccp_insert_options(sk, skb);
3017c657876SArnaldo Carvalho de Melo 
3027c657876SArnaldo Carvalho de Melo 	skb->h.raw = skb_push(skb, dccp_header_size);
3037c657876SArnaldo Carvalho de Melo 
3047c657876SArnaldo Carvalho de Melo 	dh = dccp_hdr(skb);
3057c657876SArnaldo Carvalho de Melo 	memset(dh, 0, dccp_header_size);
3067c657876SArnaldo Carvalho de Melo 
3077c657876SArnaldo Carvalho de Melo 	dh->dccph_sport	= inet_sk(sk)->sport;
3087c657876SArnaldo Carvalho de Melo 	dh->dccph_dport	= inet_rsk(req)->rmt_port;
3097690af3fSArnaldo Carvalho de Melo 	dh->dccph_doff	= (dccp_header_size +
3107690af3fSArnaldo Carvalho de Melo 			   DCCP_SKB_CB(skb)->dccpd_opt_len) / 4;
3117c657876SArnaldo Carvalho de Melo 	dh->dccph_type	= DCCP_PKT_RESPONSE;
3127c657876SArnaldo Carvalho de Melo 	dh->dccph_x	= 1;
31367e6b629SArnaldo Carvalho de Melo 	dccp_hdr_set_seq(dh, dreq->dreq_iss);
31467e6b629SArnaldo Carvalho de Melo 	dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dreq->dreq_isr);
31567e6b629SArnaldo Carvalho de Melo 	dccp_hdr_response(skb)->dccph_resp_service = dreq->dreq_service;
3167c657876SArnaldo Carvalho de Melo 
31795b81ef7SYoshifumi Nishida 	dh->dccph_checksum = dccp_v4_checksum(skb, inet_rsk(req)->loc_addr,
31895b81ef7SYoshifumi Nishida 					      inet_rsk(req)->rmt_addr);
3197c657876SArnaldo Carvalho de Melo 
3207c657876SArnaldo Carvalho de Melo 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
3217c657876SArnaldo Carvalho de Melo 	return skb;
3227c657876SArnaldo Carvalho de Melo }
3237c657876SArnaldo Carvalho de Melo 
3247c657876SArnaldo Carvalho de Melo struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
3257c657876SArnaldo Carvalho de Melo 				const enum dccp_reset_codes code)
3267c657876SArnaldo Carvalho de Melo 
3277c657876SArnaldo Carvalho de Melo {
3287c657876SArnaldo Carvalho de Melo 	struct dccp_hdr *dh;
3297c657876SArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
3307c657876SArnaldo Carvalho de Melo 	const int dccp_header_size = sizeof(struct dccp_hdr) +
3317c657876SArnaldo Carvalho de Melo 				     sizeof(struct dccp_hdr_ext) +
3327c657876SArnaldo Carvalho de Melo 				     sizeof(struct dccp_hdr_reset);
3337c657876SArnaldo Carvalho de Melo 	struct sk_buff *skb = sock_wmalloc(sk, MAX_HEADER + DCCP_MAX_OPT_LEN +
3347c657876SArnaldo Carvalho de Melo 					       dccp_header_size, 1,
3357c657876SArnaldo Carvalho de Melo 					   GFP_ATOMIC);
3367c657876SArnaldo Carvalho de Melo 	if (skb == NULL)
3377c657876SArnaldo Carvalho de Melo 		return NULL;
3387c657876SArnaldo Carvalho de Melo 
3397c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers. */
3407c657876SArnaldo Carvalho de Melo 	skb_reserve(skb, MAX_HEADER + DCCP_MAX_OPT_LEN + dccp_header_size);
3417c657876SArnaldo Carvalho de Melo 
3427c657876SArnaldo Carvalho de Melo 	skb->dst = dst_clone(dst);
3437c657876SArnaldo Carvalho de Melo 	skb->csum = 0;
3447c657876SArnaldo Carvalho de Melo 
3457c657876SArnaldo Carvalho de Melo 	dccp_inc_seqno(&dp->dccps_gss);
3467c657876SArnaldo Carvalho de Melo 
3477c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_reset_code = code;
3487c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type	   = DCCP_PKT_RESET;
3497c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_seq	   = dp->dccps_gss;
3507c657876SArnaldo Carvalho de Melo 	dccp_insert_options(sk, skb);
3517c657876SArnaldo Carvalho de Melo 
3527c657876SArnaldo Carvalho de Melo 	skb->h.raw = skb_push(skb, dccp_header_size);
3537c657876SArnaldo Carvalho de Melo 
3547c657876SArnaldo Carvalho de Melo 	dh = dccp_hdr(skb);
3557c657876SArnaldo Carvalho de Melo 	memset(dh, 0, dccp_header_size);
3567c657876SArnaldo Carvalho de Melo 
3577c657876SArnaldo Carvalho de Melo 	dh->dccph_sport	= inet_sk(sk)->sport;
3587c657876SArnaldo Carvalho de Melo 	dh->dccph_dport	= inet_sk(sk)->dport;
3597690af3fSArnaldo Carvalho de Melo 	dh->dccph_doff	= (dccp_header_size +
3607690af3fSArnaldo Carvalho de Melo 			   DCCP_SKB_CB(skb)->dccpd_opt_len) / 4;
3617c657876SArnaldo Carvalho de Melo 	dh->dccph_type	= DCCP_PKT_RESET;
3627c657876SArnaldo Carvalho de Melo 	dh->dccph_x	= 1;
3637c657876SArnaldo Carvalho de Melo 	dccp_hdr_set_seq(dh, dp->dccps_gss);
3647c657876SArnaldo Carvalho de Melo 	dccp_hdr_set_ack(dccp_hdr_ack_bits(skb), dp->dccps_gsr);
3657c657876SArnaldo Carvalho de Melo 
3667c657876SArnaldo Carvalho de Melo 	dccp_hdr_reset(skb)->dccph_reset_code = code;
3677c657876SArnaldo Carvalho de Melo 
36895b81ef7SYoshifumi Nishida 	dh->dccph_checksum = dccp_v4_checksum(skb, inet_sk(sk)->saddr,
36995b81ef7SYoshifumi Nishida 					      inet_sk(sk)->daddr);
3707c657876SArnaldo Carvalho de Melo 
3717c657876SArnaldo Carvalho de Melo 	DCCP_INC_STATS(DCCP_MIB_OUTSEGS);
3727c657876SArnaldo Carvalho de Melo 	return skb;
3737c657876SArnaldo Carvalho de Melo }
3747c657876SArnaldo Carvalho de Melo 
3757c657876SArnaldo Carvalho de Melo /*
3767c657876SArnaldo Carvalho de Melo  * Do all connect socket setups that can be done AF independent.
3777c657876SArnaldo Carvalho de Melo  */
3787c657876SArnaldo Carvalho de Melo static inline void dccp_connect_init(struct sock *sk)
3797c657876SArnaldo Carvalho de Melo {
3807c657876SArnaldo Carvalho de Melo 	struct dst_entry *dst = __sk_dst_get(sk);
3817c657876SArnaldo Carvalho de Melo 	struct inet_connection_sock *icsk = inet_csk(sk);
3827c657876SArnaldo Carvalho de Melo 
3837c657876SArnaldo Carvalho de Melo 	sk->sk_err = 0;
3847c657876SArnaldo Carvalho de Melo 	sock_reset_flag(sk, SOCK_DONE);
3857c657876SArnaldo Carvalho de Melo 
3867c657876SArnaldo Carvalho de Melo 	dccp_sync_mss(sk, dst_mtu(dst));
3877c657876SArnaldo Carvalho de Melo 
3887c657876SArnaldo Carvalho de Melo 	/*
3897c657876SArnaldo Carvalho de Melo 	 * FIXME: set dp->{dccps_swh,dccps_swl}, with
3907c657876SArnaldo Carvalho de Melo 	 * something like dccp_inc_seq
3917c657876SArnaldo Carvalho de Melo 	 */
3927c657876SArnaldo Carvalho de Melo 
3937c657876SArnaldo Carvalho de Melo 	icsk->icsk_retransmits = 0;
3947c657876SArnaldo Carvalho de Melo }
3957c657876SArnaldo Carvalho de Melo 
3967c657876SArnaldo Carvalho de Melo int dccp_connect(struct sock *sk)
3977c657876SArnaldo Carvalho de Melo {
3987c657876SArnaldo Carvalho de Melo 	struct sk_buff *skb;
3997c657876SArnaldo Carvalho de Melo 	struct inet_connection_sock *icsk = inet_csk(sk);
4007c657876SArnaldo Carvalho de Melo 
4017c657876SArnaldo Carvalho de Melo 	dccp_connect_init(sk);
4027c657876SArnaldo Carvalho de Melo 
4037c657876SArnaldo Carvalho de Melo 	skb = alloc_skb(MAX_DCCP_HEADER + 15, sk->sk_allocation);
4047c657876SArnaldo Carvalho de Melo 	if (unlikely(skb == NULL))
4057c657876SArnaldo Carvalho de Melo 		return -ENOBUFS;
4067c657876SArnaldo Carvalho de Melo 
4077c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers. */
4087c657876SArnaldo Carvalho de Melo 	skb_reserve(skb, MAX_DCCP_HEADER);
4097c657876SArnaldo Carvalho de Melo 
4107c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_REQUEST;
4117c657876SArnaldo Carvalho de Melo 	skb->csum = 0;
4127c657876SArnaldo Carvalho de Melo 
41348918a4dSHerbert Xu 	dccp_skb_entail(sk, skb);
4147c657876SArnaldo Carvalho de Melo 	dccp_transmit_skb(sk, skb_clone(skb, GFP_KERNEL));
4157c657876SArnaldo Carvalho de Melo 	DCCP_INC_STATS(DCCP_MIB_ACTIVEOPENS);
4167c657876SArnaldo Carvalho de Melo 
4177c657876SArnaldo Carvalho de Melo 	/* Timer for repeating the REQUEST until an answer. */
41827258ee5SArnaldo Carvalho de Melo 	inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
41927258ee5SArnaldo Carvalho de Melo 				  icsk->icsk_rto, DCCP_RTO_MAX);
4207c657876SArnaldo Carvalho de Melo 	return 0;
4217c657876SArnaldo Carvalho de Melo }
4227c657876SArnaldo Carvalho de Melo 
4237c657876SArnaldo Carvalho de Melo void dccp_send_ack(struct sock *sk)
4247c657876SArnaldo Carvalho de Melo {
4257c657876SArnaldo Carvalho de Melo 	/* If we have been reset, we may not send again. */
4267c657876SArnaldo Carvalho de Melo 	if (sk->sk_state != DCCP_CLOSED) {
4277c657876SArnaldo Carvalho de Melo 		struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC);
4287c657876SArnaldo Carvalho de Melo 
4297c657876SArnaldo Carvalho de Melo 		if (skb == NULL) {
4307c657876SArnaldo Carvalho de Melo 			inet_csk_schedule_ack(sk);
4317c657876SArnaldo Carvalho de Melo 			inet_csk(sk)->icsk_ack.ato = TCP_ATO_MIN;
4327690af3fSArnaldo Carvalho de Melo 			inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
4337690af3fSArnaldo Carvalho de Melo 						  TCP_DELACK_MAX,
4347690af3fSArnaldo Carvalho de Melo 						  DCCP_RTO_MAX);
4357c657876SArnaldo Carvalho de Melo 			return;
4367c657876SArnaldo Carvalho de Melo 		}
4377c657876SArnaldo Carvalho de Melo 
4387c657876SArnaldo Carvalho de Melo 		/* Reserve space for headers */
4397c657876SArnaldo Carvalho de Melo 		skb_reserve(skb, MAX_DCCP_HEADER);
4407c657876SArnaldo Carvalho de Melo 		skb->csum = 0;
4417c657876SArnaldo Carvalho de Melo 		DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_ACK;
4427c657876SArnaldo Carvalho de Melo 		dccp_transmit_skb(sk, skb);
4437c657876SArnaldo Carvalho de Melo 	}
4447c657876SArnaldo Carvalho de Melo }
4457c657876SArnaldo Carvalho de Melo 
4467c657876SArnaldo Carvalho de Melo EXPORT_SYMBOL_GPL(dccp_send_ack);
4477c657876SArnaldo Carvalho de Melo 
4487c657876SArnaldo Carvalho de Melo void dccp_send_delayed_ack(struct sock *sk)
4497c657876SArnaldo Carvalho de Melo {
4507c657876SArnaldo Carvalho de Melo 	struct inet_connection_sock *icsk = inet_csk(sk);
4517c657876SArnaldo Carvalho de Melo 	/*
4527c657876SArnaldo Carvalho de Melo 	 * FIXME: tune this timer. elapsed time fixes the skew, so no problem
4537c657876SArnaldo Carvalho de Melo 	 * with using 2s, and active senders also piggyback the ACK into a
4547c657876SArnaldo Carvalho de Melo 	 * DATAACK packet, so this is really for quiescent senders.
4557c657876SArnaldo Carvalho de Melo 	 */
4567c657876SArnaldo Carvalho de Melo 	unsigned long timeout = jiffies + 2 * HZ;
4577c657876SArnaldo Carvalho de Melo 
4587c657876SArnaldo Carvalho de Melo 	/* Use new timeout only if there wasn't a older one earlier. */
4597c657876SArnaldo Carvalho de Melo 	if (icsk->icsk_ack.pending & ICSK_ACK_TIMER) {
4607c657876SArnaldo Carvalho de Melo 		/* If delack timer was blocked or is about to expire,
4617c657876SArnaldo Carvalho de Melo 		 * send ACK now.
4627c657876SArnaldo Carvalho de Melo 		 *
4637c657876SArnaldo Carvalho de Melo 		 * FIXME: check the "about to expire" part
4647c657876SArnaldo Carvalho de Melo 		 */
4657c657876SArnaldo Carvalho de Melo 		if (icsk->icsk_ack.blocked) {
4667c657876SArnaldo Carvalho de Melo 			dccp_send_ack(sk);
4677c657876SArnaldo Carvalho de Melo 			return;
4687c657876SArnaldo Carvalho de Melo 		}
4697c657876SArnaldo Carvalho de Melo 
4707c657876SArnaldo Carvalho de Melo 		if (!time_before(timeout, icsk->icsk_ack.timeout))
4717c657876SArnaldo Carvalho de Melo 			timeout = icsk->icsk_ack.timeout;
4727c657876SArnaldo Carvalho de Melo 	}
4737c657876SArnaldo Carvalho de Melo 	icsk->icsk_ack.pending |= ICSK_ACK_SCHED | ICSK_ACK_TIMER;
4747c657876SArnaldo Carvalho de Melo 	icsk->icsk_ack.timeout = timeout;
4757c657876SArnaldo Carvalho de Melo 	sk_reset_timer(sk, &icsk->icsk_delack_timer, timeout);
4767c657876SArnaldo Carvalho de Melo }
4777c657876SArnaldo Carvalho de Melo 
478e92ae93aSArnaldo Carvalho de Melo void dccp_send_sync(struct sock *sk, const u64 seq,
479e92ae93aSArnaldo Carvalho de Melo 		    const enum dccp_pkt_type pkt_type)
4807c657876SArnaldo Carvalho de Melo {
4817c657876SArnaldo Carvalho de Melo 	/*
4827c657876SArnaldo Carvalho de Melo 	 * We are not putting this on the write queue, so
4837c657876SArnaldo Carvalho de Melo 	 * dccp_transmit_skb() will set the ownership to this
4847c657876SArnaldo Carvalho de Melo 	 * sock.
4857c657876SArnaldo Carvalho de Melo 	 */
4867c657876SArnaldo Carvalho de Melo 	struct sk_buff *skb = alloc_skb(MAX_DCCP_HEADER, GFP_ATOMIC);
4877c657876SArnaldo Carvalho de Melo 
4887c657876SArnaldo Carvalho de Melo 	if (skb == NULL)
4897c657876SArnaldo Carvalho de Melo 		/* FIXME: how to make sure the sync is sent? */
4907c657876SArnaldo Carvalho de Melo 		return;
4917c657876SArnaldo Carvalho de Melo 
4927c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers and prepare control bits. */
4937c657876SArnaldo Carvalho de Melo 	skb_reserve(skb, MAX_DCCP_HEADER);
4947c657876SArnaldo Carvalho de Melo 	skb->csum = 0;
495e92ae93aSArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type = pkt_type;
4967c657876SArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_seq = seq;
4977c657876SArnaldo Carvalho de Melo 
4987c657876SArnaldo Carvalho de Melo 	dccp_transmit_skb(sk, skb);
4997c657876SArnaldo Carvalho de Melo }
5007c657876SArnaldo Carvalho de Melo 
5017690af3fSArnaldo Carvalho de Melo /*
5027690af3fSArnaldo Carvalho de Melo  * Send a DCCP_PKT_CLOSE/CLOSEREQ. The caller locks the socket for us. This
5037690af3fSArnaldo Carvalho de Melo  * cannot be allowed to fail queueing a DCCP_PKT_CLOSE/CLOSEREQ frame under
5047690af3fSArnaldo Carvalho de Melo  * any circumstances.
5057c657876SArnaldo Carvalho de Melo  */
5067ad07e7cSArnaldo Carvalho de Melo void dccp_send_close(struct sock *sk, const int active)
5077c657876SArnaldo Carvalho de Melo {
5087c657876SArnaldo Carvalho de Melo 	struct dccp_sock *dp = dccp_sk(sk);
5097c657876SArnaldo Carvalho de Melo 	struct sk_buff *skb;
5107d877f3bSAl Viro 	const gfp_t prio = active ? GFP_KERNEL : GFP_ATOMIC;
5117c657876SArnaldo Carvalho de Melo 
5127ad07e7cSArnaldo Carvalho de Melo 	skb = alloc_skb(sk->sk_prot->max_header, prio);
5137ad07e7cSArnaldo Carvalho de Melo 	if (skb == NULL)
5147ad07e7cSArnaldo Carvalho de Melo 		return;
5157c657876SArnaldo Carvalho de Melo 
5167c657876SArnaldo Carvalho de Melo 	/* Reserve space for headers and prepare control bits. */
5177c657876SArnaldo Carvalho de Melo 	skb_reserve(skb, sk->sk_prot->max_header);
5187c657876SArnaldo Carvalho de Melo 	skb->csum = 0;
5197690af3fSArnaldo Carvalho de Melo 	DCCP_SKB_CB(skb)->dccpd_type = dp->dccps_role == DCCP_ROLE_CLIENT ?
5207690af3fSArnaldo Carvalho de Melo 					DCCP_PKT_CLOSE : DCCP_PKT_CLOSEREQ;
5217c657876SArnaldo Carvalho de Melo 
5227ad07e7cSArnaldo Carvalho de Melo 	if (active) {
52348918a4dSHerbert Xu 		dccp_skb_entail(sk, skb);
5247ad07e7cSArnaldo Carvalho de Melo 		dccp_transmit_skb(sk, skb_clone(skb, prio));
5257ad07e7cSArnaldo Carvalho de Melo 	} else
5267c657876SArnaldo Carvalho de Melo 		dccp_transmit_skb(sk, skb);
5277c657876SArnaldo Carvalho de Melo }
528