dn_getsockoptdecnet: move nf_{get/set}sockopt outside sock lock
[pandora-kernel.git] / net / decnet / af_decnet.c
index 19acd00..0b42774 100644 (file)
@@ -681,6 +681,9 @@ static int dn_create(struct net *net, struct socket *sock, int protocol,
 {
        struct sock *sk;
 
+       if (protocol < 0 || protocol > SK_PROTOCOL_MAX)
+               return -EINVAL;
+
        if (!net_eq(net, &init_net))
                return -EAFNOSUPPORT;
 
@@ -1335,6 +1338,12 @@ static int dn_setsockopt(struct socket *sock, int level, int optname, char __use
        lock_sock(sk);
        err = __dn_setsockopt(sock, level, optname, optval, optlen, 0);
        release_sock(sk);
+#ifdef CONFIG_NETFILTER
+       /* we need to exclude all possible ENOPROTOOPTs except default case */
+       if (err == -ENOPROTOOPT && optname != DSO_LINKINFO &&
+           optname != DSO_STREAM && optname != DSO_SEQPACKET)
+               err = nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
+#endif
 
        return err;
 }
@@ -1442,15 +1451,6 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation);
                break;
 
-       default:
-#ifdef CONFIG_NETFILTER
-               return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
-#endif
-       case DSO_LINKINFO:
-       case DSO_STREAM:
-       case DSO_SEQPACKET:
-               return -ENOPROTOOPT;
-
        case DSO_MAXWINDOW:
                if (optlen != sizeof(unsigned long))
                        return -EINVAL;
@@ -1498,6 +1498,12 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us
                        return -EINVAL;
                scp->info_loc = u.info;
                break;
+
+       case DSO_LINKINFO:
+       case DSO_STREAM:
+       case DSO_SEQPACKET:
+       default:
+               return -ENOPROTOOPT;
        }
 
        return 0;
@@ -1511,6 +1517,20 @@ static int dn_getsockopt(struct socket *sock, int level, int optname, char __use
        lock_sock(sk);
        err = __dn_getsockopt(sock, level, optname, optval, optlen, 0);
        release_sock(sk);
+#ifdef CONFIG_NETFILTER
+       if (err == -ENOPROTOOPT && optname != DSO_STREAM &&
+           optname != DSO_SEQPACKET && optname != DSO_CONACCEPT &&
+           optname != DSO_CONREJECT) {
+               int len;
+
+               if (get_user(len, optlen))
+                       return -EFAULT;
+
+               err = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
+               if (err >= 0)
+                       err = put_user(len, optlen);
+       }
+#endif
 
        return err;
 }
@@ -1576,26 +1596,6 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                r_data = &link;
                break;
 
-       default:
-#ifdef CONFIG_NETFILTER
-       {
-               int ret, len;
-
-               if (get_user(len, optlen))
-                       return -EFAULT;
-
-               ret = nf_getsockopt(sk, PF_DECnet, optname, optval, &len);
-               if (ret >= 0)
-                       ret = put_user(len, optlen);
-               return ret;
-       }
-#endif
-       case DSO_STREAM:
-       case DSO_SEQPACKET:
-       case DSO_CONACCEPT:
-       case DSO_CONREJECT:
-               return -ENOPROTOOPT;
-
        case DSO_MAXWINDOW:
                if (r_len > sizeof(unsigned long))
                        r_len = sizeof(unsigned long);
@@ -1627,6 +1627,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                        r_len = sizeof(unsigned char);
                r_data = &scp->info_rem;
                break;
+
+       case DSO_STREAM:
+       case DSO_SEQPACKET:
+       case DSO_CONACCEPT:
+       case DSO_CONREJECT:
+       default:
+               return -ENOPROTOOPT;
        }
 
        if (r_data) {
@@ -2354,6 +2361,8 @@ static const struct proto_ops dn_proto_ops = {
        .sendpage =     sock_no_sendpage,
 };
 
+void dn_register_sysctl_skeleton(void);
+void dn_unregister_sysctl_skeleton(void);
 void dn_register_sysctl(void);
 void dn_unregister_sysctl(void);
 
@@ -2374,6 +2383,7 @@ static int __init decnet_init(void)
        if (rc != 0)
                goto out;
 
+       dn_register_sysctl_skeleton();
        dn_neigh_init();
        dn_dev_init();
        dn_route_init();
@@ -2413,6 +2423,7 @@ static void __exit decnet_exit(void)
        dn_fib_cleanup();
 
        proc_net_remove(&init_net, "decnet");
+       dn_unregister_sysctl_skeleton();
 
        proto_unregister(&dn_proto);