patch-2.3.18 linux/net/core/netfilter.c
Next file: linux/net/core/sock.c
Previous file: linux/net/atm/tunable.h
Back to the patch index
Back to the overall index
- Lines: 171
- Date:
Wed Sep 8 11:51:22 1999
- Orig file:
v2.3.17/linux/net/core/netfilter.c
- Orig date:
Tue Aug 31 17:29:15 1999
diff -u --recursive --new-file v2.3.17/linux/net/core/netfilter.c linux/net/core/netfilter.c
@@ -16,7 +16,7 @@
#include <linux/interrupt.h>
#include <linux/if.h>
#include <linux/netdevice.h>
-#include <asm/spinlock.h>
+#include <linux/spinlock.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -47,6 +47,7 @@
};
static rwlock_t nf_lock = RW_LOCK_UNLOCKED;
+static DECLARE_MUTEX(nf_sockopt_mutex);
struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
static LIST_HEAD(nf_sockopts);
@@ -91,15 +92,15 @@
write_unlock_bh(&nf_lock);
}
-/* Do inclusive ranges overlap? */
+/* Do exclusive ranges overlap? */
static inline int overlap(int min1, int max1, int min2, int max2)
{
- return (min1 >= min2 && min1 <= max2)
- || (max1 >= min2 && max1 <= max2);
+ return (min1 >= min2 && min1 < max2)
+ || (max1 > min2 && max1 <= max2);
}
-/* Functions to register setsockopt ranges (inclusive). */
-int nf_register_sockopt(struct nf_setsockopt_ops *reg)
+/* Functions to register sockopt ranges (exclusive). */
+int nf_register_sockopt(struct nf_sockopt_ops *reg)
{
struct list_head *i;
int ret = 0;
@@ -109,33 +110,44 @@
NFDEBUG("nf_register_sockopt: bad val: pf=%i.\n", reg->pf);
return -EINVAL;
}
- if (reg->optmin > reg->optmax) {
- NFDEBUG("nf_register_sockopt: bad val: min=%i max=%i.\n",
- reg->optmin, reg->optmax);
+ if (reg->set_optmin > reg->set_optmax) {
+ NFDEBUG("nf_register_sockopt: bad set val: min=%i max=%i.\n",
+ reg->set_optmin, reg->set_optmax);
+ return -EINVAL;
+ }
+ if (reg->get_optmin > reg->get_optmax) {
+ NFDEBUG("nf_register_sockopt: bad get val: min=%i max=%i.\n",
+ reg->get_optmin, reg->get_optmax);
return -EINVAL;
}
#endif
- write_lock_bh(&nf_lock);
+ if (down_interruptible(&nf_sockopt_mutex) != 0)
+ return -EINTR;
+
for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) {
- struct nf_setsockopt_ops *ops = (struct nf_setsockopt_ops *)i;
+ struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
if (ops->pf == reg->pf
- && overlap(ops->optmin, ops->optmax,
- reg->optmin, reg->optmax)) {
- NFDEBUG("nf_register_sockopt overlap: %u-%u v %u-%u\n",
- ops->optmin, ops->optmax,
- reg->optmin, reg->optmax);
+ && (overlap(ops->set_optmin, ops->set_optmax,
+ reg->set_optmin, reg->set_optmax)
+ || overlap(ops->get_optmin, ops->get_optmax,
+ reg->get_optmin, reg->get_optmax))) {
+ NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n",
+ ops->set_optmin, ops->set_optmax,
+ ops->get_optmin, ops->get_optmax,
+ reg->set_optmin, reg->set_optmax,
+ reg->get_optmin, reg->get_optmax);
ret = -EBUSY;
goto out;
}
}
-
+
list_add(®->list, &nf_sockopts);
out:
- write_unlock_bh(&nf_lock);
+ up(&nf_sockopt_mutex);
return ret;
}
-void nf_unregister_sockopt(struct nf_setsockopt_ops *reg)
+void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
{
#ifdef CONFIG_NETFILTER_DEBUG
if (reg->pf<0 || reg->pf>=NPROTO) {
@@ -143,9 +155,10 @@
return;
}
#endif
- write_lock_bh(&nf_lock);
+ /* No point being interruptible: we're probably in cleanup_module() */
+ down(&nf_sockopt_mutex);
list_del(®->list);
- write_unlock_bh(&nf_lock);
+ up(&nf_sockopt_mutex);
}
#ifdef CONFIG_NETFILTER_DEBUG
@@ -290,8 +303,9 @@
read_unlock_bh(&nf_lock);
}
-/* Call setsockopt() */
-int nf_setsockopt(int pf, int val, char *opt, unsigned int len)
+/* Call get/setsockopt() */
+static int nf_sockopt(struct sock *sk, int pf, int val,
+ char *opt, int *len, int get)
{
struct list_head *i;
int ret;
@@ -299,19 +313,42 @@
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- read_lock_bh(&nf_lock);
+ if (down_interruptible(&nf_sockopt_mutex) != 0)
+ return -EINTR;
+
for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) {
- struct nf_setsockopt_ops *ops = (struct nf_setsockopt_ops *)i;
- if (ops->pf == pf
- && val >= ops->optmin && val <= ops->optmax) {
- ret = ops->fn(val, opt, len);
- goto out;
+ struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
+ if (ops->pf == pf) {
+ if (get) {
+ if (val >= ops->get_optmin
+ && val < ops->get_optmax) {
+ ret = ops->get(sk, val, opt, len);
+ goto out;
+ }
+ } else {
+ if (val >= ops->set_optmin
+ && val < ops->set_optmax) {
+ ret = ops->set(sk, val, opt, *len);
+ goto out;
+ }
+ }
}
}
ret = -ENOPROTOOPT;
out:
- read_unlock_bh(&nf_lock);
+ up(&nf_sockopt_mutex);
return ret;
+}
+
+int nf_setsockopt(struct sock *sk, int pf, int val, char *opt,
+ int len)
+{
+ return nf_sockopt(sk, pf, val, opt, &len, 0);
+}
+
+int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len)
+{
+ return nf_sockopt(sk, pf, val, opt, len, 1);
}
static unsigned int nf_iterate(struct list_head *head,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)