fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / net / netfilter / nf_sockopt.c
index 61a833a..c2e44e9 100644 (file)
@@ -1,9 +1,9 @@
-#include <linux/config.h>
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/skbuff.h>
 #include <linux/netfilter.h>
+#include <linux/mutex.h>
 #include <net/sock.h>
 
 #include "nf_internals.h"
@@ -11,7 +11,7 @@
 /* Sockopts only registered and called from user context, so
    net locking would be overkill.  Also, [gs]etsockopt calls may
    sleep. */
-static DECLARE_MUTEX(nf_sockopt_mutex);
+static DEFINE_MUTEX(nf_sockopt_mutex);
 static LIST_HEAD(nf_sockopts);
 
 /* Do exclusive ranges overlap? */
@@ -26,7 +26,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg)
        struct list_head *i;
        int ret = 0;
 
-       if (down_interruptible(&nf_sockopt_mutex) != 0)
+       if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
        list_for_each(i, &nf_sockopts) {
@@ -48,7 +48,7 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg)
 
        list_add(&reg->list, &nf_sockopts);
 out:
-       up(&nf_sockopt_mutex);
+       mutex_unlock(&nf_sockopt_mutex);
        return ret;
 }
 EXPORT_SYMBOL(nf_register_sockopt);
@@ -57,18 +57,18 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
 {
        /* No point being interruptible: we're probably in cleanup_module() */
  restart:
-       down(&nf_sockopt_mutex);
+       mutex_lock(&nf_sockopt_mutex);
        if (reg->use != 0) {
                /* To be woken by nf_sockopt call... */
                /* FIXME: Stuart Young's name appears gratuitously. */
                set_current_state(TASK_UNINTERRUPTIBLE);
                reg->cleanup_task = current;
-               up(&nf_sockopt_mutex);
+               mutex_unlock(&nf_sockopt_mutex);
                schedule();
                goto restart;
        }
        list_del(&reg->list);
-       up(&nf_sockopt_mutex);
+       mutex_unlock(&nf_sockopt_mutex);
 }
 EXPORT_SYMBOL(nf_unregister_sockopt);
 
@@ -80,7 +80,7 @@ static int nf_sockopt(struct sock *sk, int pf, int val,
        struct nf_sockopt_ops *ops;
        int ret;
 
-       if (down_interruptible(&nf_sockopt_mutex) != 0)
+       if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
                return -EINTR;
 
        list_for_each(i, &nf_sockopts) {
@@ -90,7 +90,7 @@ static int nf_sockopt(struct sock *sk, int pf, int val,
                                if (val >= ops->get_optmin
                                    && val < ops->get_optmax) {
                                        ops->use++;
-                                       up(&nf_sockopt_mutex);
+                                       mutex_unlock(&nf_sockopt_mutex);
                                        ret = ops->get(sk, val, opt, len);
                                        goto out;
                                }
@@ -98,22 +98,22 @@ static int nf_sockopt(struct sock *sk, int pf, int val,
                                if (val >= ops->set_optmin
                                    && val < ops->set_optmax) {
                                        ops->use++;
-                                       up(&nf_sockopt_mutex);
+                                       mutex_unlock(&nf_sockopt_mutex);
                                        ret = ops->set(sk, val, opt, *len);
                                        goto out;
                                }
                        }
                }
        }
-       up(&nf_sockopt_mutex);
+       mutex_unlock(&nf_sockopt_mutex);
        return -ENOPROTOOPT;
        
  out:
-       down(&nf_sockopt_mutex);
+       mutex_lock(&nf_sockopt_mutex);
        ops->use--;
        if (ops->cleanup_task)
                wake_up_process(ops->cleanup_task);
-       up(&nf_sockopt_mutex);
+       mutex_unlock(&nf_sockopt_mutex);
        return ret;
 }
 
@@ -130,3 +130,72 @@ int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len)
 }
 EXPORT_SYMBOL(nf_getsockopt);
 
+#ifdef CONFIG_COMPAT
+static int compat_nf_sockopt(struct sock *sk, int pf, int val,
+                            char __user *opt, int *len, int get)
+{
+       struct list_head *i;
+       struct nf_sockopt_ops *ops;
+       int ret;
+
+       if (mutex_lock_interruptible(&nf_sockopt_mutex) != 0)
+               return -EINTR;
+
+       list_for_each(i, &nf_sockopts) {
+               ops = (struct nf_sockopt_ops *)i;
+               if (ops->pf == pf) {
+                       if (get) {
+                               if (val >= ops->get_optmin
+                                   && val < ops->get_optmax) {
+                                       ops->use++;
+                                       mutex_unlock(&nf_sockopt_mutex);
+                                       if (ops->compat_get)
+                                               ret = ops->compat_get(sk,
+                                                       val, opt, len);
+                                       else
+                                               ret = ops->get(sk,
+                                                       val, opt, len);
+                                       goto out;
+                               }
+                       } else {
+                               if (val >= ops->set_optmin
+                                   && val < ops->set_optmax) {
+                                       ops->use++;
+                                       mutex_unlock(&nf_sockopt_mutex);
+                                       if (ops->compat_set)
+                                               ret = ops->compat_set(sk,
+                                                       val, opt, *len);
+                                       else
+                                               ret = ops->set(sk,
+                                                       val, opt, *len);
+                                       goto out;
+                               }
+                       }
+               }
+       }
+       mutex_unlock(&nf_sockopt_mutex);
+       return -ENOPROTOOPT;
+
+ out:
+       mutex_lock(&nf_sockopt_mutex);
+       ops->use--;
+       if (ops->cleanup_task)
+               wake_up_process(ops->cleanup_task);
+       mutex_unlock(&nf_sockopt_mutex);
+       return ret;
+}
+
+int compat_nf_setsockopt(struct sock *sk, int pf,
+               int val, char __user *opt, int len)
+{
+       return compat_nf_sockopt(sk, pf, val, opt, &len, 0);
+}
+EXPORT_SYMBOL(compat_nf_setsockopt);
+
+int compat_nf_getsockopt(struct sock *sk, int pf,
+               int val, char __user *opt, int *len)
+{
+       return compat_nf_sockopt(sk, pf, val, opt, len, 1);
+}
+EXPORT_SYMBOL(compat_nf_getsockopt);
+#endif