Commit 259db53b authored by Xin Long's avatar Xin Long Committed by Jakub Kicinski
Browse files

sctp: support for sending packet over udp6 sock



This one basically does the similar things in sctp_v6_xmit as does for
udp4 sock in the last patch, just note that:

  1. label needs to be calculated, as it's the param of
     udp_tunnel6_xmit_skb().

  2. The 'nocheck' param of udp_tunnel6_xmit_skb() is false, as
     required by RFC.

v1->v2:
  - Use sp->udp_port instead in sctp_v6_xmit(), which is more safe.

Signed-off-by: default avatarXin Long <lucien.xin@gmail.com>
Acked-by: default avatarMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 600af7fd
Loading
Loading
Loading
Loading
+32 −11
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@
#include <net/inet_common.h>
#include <net/inet_ecn.h>
#include <net/sctp/sctp.h>
#include <net/udp_tunnel.h>

#include <linux/uaccess.h>

@@ -191,35 +192,55 @@ static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
	return ret;
}

static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *t)
{
	struct dst_entry *dst = dst_clone(t->dst);
	struct flowi6 *fl6 = &t->fl.u.ip6;
	struct sock *sk = skb->sk;
	struct ipv6_pinfo *np = inet6_sk(sk);
	struct flowi6 *fl6 = &transport->fl.u.ip6;
	__u8 tclass = np->tclass;
	int res;
	__be32 label;

	pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
		 skb->len, &fl6->saddr, &fl6->daddr);

	if (transport->dscp & SCTP_DSCP_SET_MASK)
		tclass = transport->dscp & SCTP_DSCP_VAL_MASK;
	if (t->dscp & SCTP_DSCP_SET_MASK)
		tclass = t->dscp & SCTP_DSCP_VAL_MASK;

	if (INET_ECN_is_capable(tclass))
		IP6_ECN_flow_xmit(sk, fl6->flowlabel);

	if (!(transport->param_flags & SPP_PMTUD_ENABLE))
	if (!(t->param_flags & SPP_PMTUD_ENABLE))
		skb->ignore_df = 1;

	SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);

	if (!t->encap_port || !sctp_sk(sk)->udp_port) {
		int res;

		skb_dst_set(skb, dst);
		rcu_read_lock();
	res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt),
		res = ip6_xmit(sk, skb, fl6, sk->sk_mark,
			       rcu_dereference(np->opt),
			       tclass, sk->sk_priority);
		rcu_read_unlock();
		return res;
	}

	if (skb_is_gso(skb))
		skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM;

	skb->encapsulation = 1;
	skb_reset_inner_mac_header(skb);
	skb_reset_inner_transport_header(skb);
	skb_set_inner_ipproto(skb, IPPROTO_SCTP);
	label = ip6_make_flowlabel(sock_net(sk), skb, fl6->flowlabel, true, fl6);

	return udp_tunnel6_xmit_skb(dst, sk, skb, NULL, &fl6->saddr,
				    &fl6->daddr, tclass, ip6_dst_hoplimit(dst),
				    label, sctp_sk(sk)->udp_port, t->encap_port, false);
}

/* Returns the dst cache entry for the given source and destination ip
 * addresses.
 */