]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
sctp: support for sending packet over udp6 sock
authorXin Long <lucien.xin@gmail.com>
Thu, 29 Oct 2020 07:05:07 +0000 (15:05 +0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 30 Oct 2020 22:24:35 +0000 (15:24 -0700)
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>
net/sctp/ipv6.c

index a064bf252b170ccc027934de532fcb144f429b28..814754d7cab5b7d01b07a65aefa32712028613b5 100644 (file)
@@ -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