]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - net/sctp/ipv6.c
Merge tag 'selinux-pr-20180403' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-hirsute-kernel.git] / net / sctp / ipv6.c
index 0d873c58e5167a8855d62de14d88dc738bc70e48..6dd976c8ab611943fbbcfc3800d330fa68c801b0 100644 (file)
@@ -427,6 +427,41 @@ static void sctp_v6_copy_addrlist(struct list_head *addrlist,
        rcu_read_unlock();
 }
 
+/* Copy over any ip options */
+static void sctp_v6_copy_ip_options(struct sock *sk, struct sock *newsk)
+{
+       struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
+       struct ipv6_txoptions *opt;
+
+       newnp = inet6_sk(newsk);
+
+       rcu_read_lock();
+       opt = rcu_dereference(np->opt);
+       if (opt) {
+               opt = ipv6_dup_options(newsk, opt);
+               if (!opt)
+                       pr_err("%s: Failed to copy ip options\n", __func__);
+       }
+       RCU_INIT_POINTER(newnp->opt, opt);
+       rcu_read_unlock();
+}
+
+/* Account for the IP options */
+static int sctp_v6_ip_options_len(struct sock *sk)
+{
+       struct ipv6_pinfo *np = inet6_sk(sk);
+       struct ipv6_txoptions *opt;
+       int len = 0;
+
+       rcu_read_lock();
+       opt = rcu_dereference(np->opt);
+       if (opt)
+               len = opt->opt_flen + opt->opt_nflen;
+
+       rcu_read_unlock();
+       return len;
+}
+
 /* Initialize a sockaddr_storage from in incoming skb. */
 static void sctp_v6_from_skb(union sctp_addr *addr, struct sk_buff *skb,
                             int is_saddr)
@@ -666,7 +701,6 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
        struct sock *newsk;
        struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
        struct sctp6_sock *newsctp6sk;
-       struct ipv6_txoptions *opt;
 
        newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, kern);
        if (!newsk)
@@ -689,12 +723,7 @@ static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
        newnp->ipv6_ac_list = NULL;
        newnp->ipv6_fl_list = NULL;
 
-       rcu_read_lock();
-       opt = rcu_dereference(np->opt);
-       if (opt)
-               opt = ipv6_dup_options(newsk, opt);
-       RCU_INIT_POINTER(newnp->opt, opt);
-       rcu_read_unlock();
+       sctp_v6_copy_ip_options(sk, newsk);
 
        /* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
         * and getpeername().
@@ -1041,6 +1070,7 @@ static struct sctp_af sctp_af_inet6 = {
        .ecn_capable       = sctp_v6_ecn_capable,
        .net_header_len    = sizeof(struct ipv6hdr),
        .sockaddr_len      = sizeof(struct sockaddr_in6),
+       .ip_options_len    = sctp_v6_ip_options_len,
 #ifdef CONFIG_COMPAT
        .compat_setsockopt = compat_ipv6_setsockopt,
        .compat_getsockopt = compat_ipv6_getsockopt,
@@ -1059,6 +1089,7 @@ static struct sctp_pf sctp_pf_inet6 = {
        .addr_to_user  = sctp_v6_addr_to_user,
        .to_sk_saddr   = sctp_v6_to_sk_saddr,
        .to_sk_daddr   = sctp_v6_to_sk_daddr,
+       .copy_ip_options = sctp_v6_copy_ip_options,
        .af            = &sctp_af_inet6,
 };