Merge tag 'efi_updates_for_v5.11' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / net / sctp / protocol.c
index 2583323..6f2bbfe 100644 (file)
@@ -44,6 +44,7 @@
 #include <net/addrconf.h>
 #include <net/inet_common.h>
 #include <net/inet_ecn.h>
+#include <net/udp_tunnel.h>
 
 #define MAX_SCTP_PORT_HASH_ENTRIES (64 * 1024)
 
@@ -840,6 +841,92 @@ static int sctp_ctl_sock_init(struct net *net)
        return 0;
 }
 
+static int sctp_udp_rcv(struct sock *sk, struct sk_buff *skb)
+{
+       SCTP_INPUT_CB(skb)->encap_port = udp_hdr(skb)->source;
+
+       skb_set_transport_header(skb, sizeof(struct udphdr));
+       sctp_rcv(skb);
+       return 0;
+}
+
+static int sctp_udp_err_lookup(struct sock *sk, struct sk_buff *skb)
+{
+       struct sctp_association *asoc;
+       struct sctp_transport *t;
+       int family;
+
+       skb->transport_header += sizeof(struct udphdr);
+       family = (ip_hdr(skb)->version == 4) ? AF_INET : AF_INET6;
+       sk = sctp_err_lookup(dev_net(skb->dev), family, skb, sctp_hdr(skb),
+                            &asoc, &t);
+       if (!sk)
+               return -ENOENT;
+
+       sctp_err_finish(sk, t);
+       return 0;
+}
+
+int sctp_udp_sock_start(struct net *net)
+{
+       struct udp_tunnel_sock_cfg tuncfg = {NULL};
+       struct udp_port_cfg udp_conf = {0};
+       struct socket *sock;
+       int err;
+
+       udp_conf.family = AF_INET;
+       udp_conf.local_ip.s_addr = htonl(INADDR_ANY);
+       udp_conf.local_udp_port = htons(net->sctp.udp_port);
+       err = udp_sock_create(net, &udp_conf, &sock);
+       if (err) {
+               pr_err("Failed to create the SCTP UDP tunneling v4 sock\n");
+               return err;
+       }
+
+       tuncfg.encap_type = 1;
+       tuncfg.encap_rcv = sctp_udp_rcv;
+       tuncfg.encap_err_lookup = sctp_udp_err_lookup;
+       setup_udp_tunnel_sock(net, sock, &tuncfg);
+       net->sctp.udp4_sock = sock->sk;
+
+#if IS_ENABLED(CONFIG_IPV6)
+       memset(&udp_conf, 0, sizeof(udp_conf));
+
+       udp_conf.family = AF_INET6;
+       udp_conf.local_ip6 = in6addr_any;
+       udp_conf.local_udp_port = htons(net->sctp.udp_port);
+       udp_conf.use_udp6_rx_checksums = true;
+       udp_conf.ipv6_v6only = true;
+       err = udp_sock_create(net, &udp_conf, &sock);
+       if (err) {
+               pr_err("Failed to create the SCTP UDP tunneling v6 sock\n");
+               udp_tunnel_sock_release(net->sctp.udp4_sock->sk_socket);
+               net->sctp.udp4_sock = NULL;
+               return err;
+       }
+
+       tuncfg.encap_type = 1;
+       tuncfg.encap_rcv = sctp_udp_rcv;
+       tuncfg.encap_err_lookup = sctp_udp_err_lookup;
+       setup_udp_tunnel_sock(net, sock, &tuncfg);
+       net->sctp.udp6_sock = sock->sk;
+#endif
+
+       return 0;
+}
+
+void sctp_udp_sock_stop(struct net *net)
+{
+       if (net->sctp.udp4_sock) {
+               udp_tunnel_sock_release(net->sctp.udp4_sock->sk_socket);
+               net->sctp.udp4_sock = NULL;
+       }
+       if (net->sctp.udp6_sock) {
+               udp_tunnel_sock_release(net->sctp.udp6_sock->sk_socket);
+               net->sctp.udp6_sock = NULL;
+       }
+}
+
 /* Register address family specific functions. */
 int sctp_register_af(struct sctp_af *af)
 {
@@ -971,25 +1058,44 @@ static int sctp_inet_supported_addrs(const struct sctp_sock *opt,
 }
 
 /* Wrapper routine that calls the ip transmit routine. */
-static inline int sctp_v4_xmit(struct sk_buff *skb,
-                              struct sctp_transport *transport)
+static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t)
 {
-       struct inet_sock *inet = inet_sk(skb->sk);
+       struct dst_entry *dst = dst_clone(t->dst);
+       struct flowi4 *fl4 = &t->fl.u.ip4;
+       struct sock *sk = skb->sk;
+       struct inet_sock *inet = inet_sk(sk);
        __u8 dscp = inet->tos;
+       __be16 df = 0;
 
        pr_debug("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb,
-                skb->len, &transport->fl.u.ip4.saddr,
-                &transport->fl.u.ip4.daddr);
+                skb->len, &fl4->saddr, &fl4->daddr);
 
-       if (transport->dscp & SCTP_DSCP_SET_MASK)
-               dscp = transport->dscp & SCTP_DSCP_VAL_MASK;
+       if (t->dscp & SCTP_DSCP_SET_MASK)
+               dscp = t->dscp & SCTP_DSCP_VAL_MASK;
+
+       inet->pmtudisc = t->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO
+                                                          : IP_PMTUDISC_DONT;
+       SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
 
-       inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ?
-                        IP_PMTUDISC_DO : IP_PMTUDISC_DONT;
+       if (!t->encap_port || !sctp_sk(sk)->udp_port) {
+               skb_dst_set(skb, dst);
+               return __ip_queue_xmit(sk, skb, &t->fl, dscp);
+       }
 
-       SCTP_INC_STATS(sock_net(&inet->sk), SCTP_MIB_OUTSCTPPACKS);
+       if (skb_is_gso(skb))
+               skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM;
 
-       return __ip_queue_xmit(&inet->sk, skb, &transport->fl, dscp);
+       if (ip_dont_fragment(sk, dst) && !skb->ignore_df)
+               df = htons(IP_DF);
+
+       skb->encapsulation = 1;
+       skb_reset_inner_mac_header(skb);
+       skb_reset_inner_transport_header(skb);
+       skb_set_inner_ipproto(skb, IPPROTO_SCTP);
+       udp_tunnel_xmit_skb((struct rtable *)dst, sk, skb, fl4->saddr,
+                           fl4->daddr, dscp, ip4_dst_hoplimit(dst), df,
+                           sctp_sk(sk)->udp_port, t->encap_port, false, false);
+       return 0;
 }
 
 static struct sctp_af sctp_af_inet;
@@ -1054,9 +1160,15 @@ static struct inet_protosw sctp_stream_protosw = {
        .flags      = SCTP_PROTOSW_FLAG
 };
 
+static int sctp4_rcv(struct sk_buff *skb)
+{
+       SCTP_INPUT_CB(skb)->encap_port = 0;
+       return sctp_rcv(skb);
+}
+
 /* Register with IP layer.  */
 static const struct net_protocol sctp_protocol = {
-       .handler     = sctp_rcv,
+       .handler     = sctp4_rcv,
        .err_handler = sctp_v4_err,
        .no_policy   = 1,
        .netns_ok    = 1,
@@ -1271,6 +1383,12 @@ static int __net_init sctp_defaults_init(struct net *net)
        /* Enable ECN by default. */
        net->sctp.ecn_enable = 1;
 
+       /* Set UDP tunneling listening port to 0 by default */
+       net->sctp.udp_port = 0;
+
+       /* Set remote encap port to 0 by default */
+       net->sctp.encap_port = 0;
+
        /* Set SCOPE policy to enabled */
        net->sctp.scope_policy = SCTP_SCOPE_POLICY_ENABLE;