]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - net/netfilter/nf_sockopt.c
[NET]: {get|set}sockopt compatibility layer
[net-next-2.6.git] / net / netfilter / nf_sockopt.c
index 0e5c5e2047995bf03c422ef68f4233b38154220d..da1cd48de2166936d843efcfb8f3f40b5a6108cf 100644 (file)
@@ -131,3 +131,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