summaryrefslogtreecommitdiff
path: root/net/sctp/ipv6.c
diff options
context:
space:
mode:
authorXin Long <lucien.xin@gmail.com>2020-10-29 15:05:07 +0800
committerJakub Kicinski <kuba@kernel.org>2020-10-30 15:24:35 -0700
commit259db53ba5933a2a507238c47ffa52c906c27df0 (patch)
treee4fc0033711c22cebfa3e10b19474b4b56e351b2 /net/sctp/ipv6.c
parent600af7fd809ad2a307b6c53b2a3e45453a75cdb6 (diff)
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: Xin Long <lucien.xin@gmail.com> Acked-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: Jakub Kicinski <kuba@kernel.org>
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r--net/sctp/ipv6.c43
1 files changed, 32 insertions, 11 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index a064bf252b17..814754d7cab5 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -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,33 +192,53 @@ out:
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);
- rcu_read_lock();
- res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt),
- tclass, sk->sk_priority);
- rcu_read_unlock();
- return res;
+ 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),
+ 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