]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/ipv6/ipv6_sockglue.c
cfq-iosched: fix RCU problem in cfq_cic_lookup()
[linux-2.6-omap-h63xx.git] / net / ipv6 / ipv6_sockglue.c
index 2f1244dc5ebfb8129856b68eef3dbec19e952863..56d55fecf8ec49d49a79e804b0129e8570441df5 100644 (file)
@@ -52,6 +52,7 @@
 #include <net/udp.h>
 #include <net/udplite.h>
 #include <net/xfrm.h>
+#include <net/compat.h>
 
 #include <asm/uaccess.h>
 
@@ -103,6 +104,29 @@ int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *))
        return 0;
 }
 
+static
+struct ipv6_txoptions *ipv6_update_options(struct sock *sk,
+                                          struct ipv6_txoptions *opt)
+{
+       if (inet_sk(sk)->is_icsk) {
+               if (opt &&
+                   !((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) &&
+                   inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
+                       struct inet_connection_sock *icsk = inet_csk(sk);
+                       icsk->icsk_ext_hdr_len = opt->opt_flen + opt->opt_nflen;
+                       icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
+               }
+               opt = xchg(&inet6_sk(sk)->opt, opt);
+       } else {
+               write_lock(&sk->sk_dst_lock);
+               opt = xchg(&inet6_sk(sk)->opt, opt);
+               write_unlock(&sk->sk_dst_lock);
+       }
+       sk_dst_reset(sk);
+
+       return opt;
+}
+
 static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                    char __user *optval, int optlen)
 {
@@ -351,25 +375,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                }
 
                retv = 0;
-               if (inet_sk(sk)->is_icsk) {
-                       if (opt) {
-                               struct inet_connection_sock *icsk = inet_csk(sk);
-                               if (!((1 << sk->sk_state) &
-                                     (TCPF_LISTEN | TCPF_CLOSE))
-                                   && inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
-                                       icsk->icsk_ext_hdr_len =
-                                               opt->opt_flen + opt->opt_nflen;
-                                       icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
-                               }
-                       }
-                       opt = xchg(&np->opt, opt);
-                       sk_dst_reset(sk);
-               } else {
-                       write_lock(&sk->sk_dst_lock);
-                       opt = xchg(&np->opt, opt);
-                       write_unlock(&sk->sk_dst_lock);
-                       sk_dst_reset(sk);
-               }
+               opt = ipv6_update_options(sk, opt);
 sticky_done:
                if (opt)
                        sock_kfree_s(sk, opt, opt->tot_len);
@@ -415,26 +421,7 @@ sticky_done:
                        goto done;
 update:
                retv = 0;
-               if (inet_sk(sk)->is_icsk) {
-                       if (opt) {
-                               struct inet_connection_sock *icsk = inet_csk(sk);
-                               if (!((1 << sk->sk_state) &
-                                     (TCPF_LISTEN | TCPF_CLOSE))
-                                   && inet_sk(sk)->daddr != LOOPBACK4_IPV6) {
-                                       icsk->icsk_ext_hdr_len =
-                                               opt->opt_flen + opt->opt_nflen;
-                                       icsk->icsk_sync_mss(sk, icsk->icsk_pmtu_cookie);
-                               }
-                       }
-                       opt = xchg(&np->opt, opt);
-                       sk_dst_reset(sk);
-               } else {
-                       write_lock(&sk->sk_dst_lock);
-                       opt = xchg(&np->opt, opt);
-                       write_unlock(&sk->sk_dst_lock);
-                       sk_dst_reset(sk);
-               }
-
+               opt = ipv6_update_options(sk, opt);
 done:
                if (opt)
                        sock_kfree_s(sk, opt, opt->tot_len);
@@ -793,6 +780,10 @@ int compat_ipv6_setsockopt(struct sock *sk, int level, int optname,
        if (level != SOL_IPV6)
                return -ENOPROTOOPT;
 
+       if (optname >= MCAST_JOIN_GROUP && optname <= MCAST_MSFILTER)
+               return compat_mc_setsockopt(sk, level, optname, optval, optlen,
+                       ipv6_setsockopt);
+
        err = do_ipv6_setsockopt(sk, level, optname, optval, optlen);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */
@@ -1136,6 +1127,10 @@ int compat_ipv6_getsockopt(struct sock *sk, int level, int optname,
        if (level != SOL_IPV6)
                return -ENOPROTOOPT;
 
+       if (optname == MCAST_MSFILTER)
+               return compat_mc_getsockopt(sk, level, optname, optval, optlen,
+                       ipv6_getsockopt);
+
        err = do_ipv6_getsockopt(sk, level, optname, optval, optlen);
 #ifdef CONFIG_NETFILTER
        /* we need to exclude all possible ENOPROTOOPTs except default case */