* Re: [RFC PATCH] convert ebt_ulog to nfnetlink_log
From: bdschuym@pandora.be @ 2005-08-08 9:06 UTC (permalink / raw)
To: Harald Welte; +Cc: Linux Netdev List, Netfilter Development Mailinglist
(using webmail)
>----- Oorspronkelijk bericht -----
>Van: Harald Welte [mailto:laforge@netfilter.org]
>Ok, so this is actually the opposite problem of the ipt_physdev.c
>problem. Here we have the physical device, but not the bridge group.
>
>This means we have to handle two separate cases:
>
>1) when nf_log_packet() gets called from the bridging code
> indev == eth0
> outdev == eth1
> -> we need to resolve br0 from dev->br_port member
>
>2) when nf_log_packet() gets called from the ipv4 code:
> indev == br0
> outdev == br0
> -> we need to resolve ethX from skb->nf_bridge member
>
>If I'm now correct, what about the following [reverse] patch (also
>attached the whole resulting file for your reference, since you don't
>have access to the tree).
There is one case missing: the brouter case. If br0=eth0+eth1 and a packet arrives at eth0 (not br0) in the IP code (not the bridge code), then the indev must be eth0, not br0.
How about something like this?
if (pf == PF_BRIDGE) { /* Called from ebtables */
NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
sizeof(tmp_uint), &tmp_uint);
tmp_uint = htonl(indev->br_port->br->dev->ifindex);
NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV,
sizeof(tmp_uint), &tmp_uint);
} else {
NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV,
sizeof(tmp_uint), &tmp_uint);
if (skb->nf_bridge && skb->nf_bridge->physindev)
/* Called inside bridge code, but not from ebtables. */
tmp_uint = htonl(skb->nf_bridge->physindev->ifindex);
NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
sizeof(tmp_uint), &tmp_uint);
}
cheers,
Bart
^ permalink raw reply
* Re: [RFC PATCH] convert ebt_ulog to nfnetlink_log
From: Harald Welte @ 2005-08-08 8:16 UTC (permalink / raw)
To: Bart De Schuymer; +Cc: Linux Netdev List, Netfilter Development Mailinglist
In-Reply-To: <1123484260.3686.1.camel@localhost.localdomain>
[-- Attachment #1.1: Type: text/plain, Size: 1678 bytes --]
[removing kaber and davem from cc list]
On Mon, Aug 08, 2005 at 06:57:40AM +0000, Bart De Schuymer wrote:
> > So I think it should reflect exactly what you currently do in ebt_ulog.
> > The only diference is that you now get the ifindex and not the device
> > name string.
>
> These two code fragments do not do the same thing. If indev is a bridge
> port (meaning indev->br_port != NULL), then the NFULA_IFINDEX_PHYSINDEV
> must be indev, while the NFULA_IFINDEX_INDEV must be in->br_port->br-
> >dev->name.
> If indev is not a bridge port, the ebt_ulog code makes
> NFULA_IFINDEX_PHYSINDEV and NFULA_IFINDEX_INDEV the same (indev).
Ok, so this is actually the opposite problem of the ipt_physdev.c
problem. Here we have the physical device, but not the bridge group.
This means we have to handle two separate cases:
1) when nf_log_packet() gets called from the bridging code
indev == eth0
outdev == eth1
-> we need to resolve br0 from dev->br_port member
2) when nf_log_packet() gets called from the ipv4 code:
indev == br0
outdev == br0
-> we need to resolve ethX from skb->nf_bridge member
If I'm now correct, what about the following [reverse] patch (also
attached the whole resulting file for your reference, since you don't
have access to the tree).
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #1.2: bridge2.diff --]
[-- Type: text/plain, Size: 7460 bytes --]
diff --git a/include/linux/netfilter/nfnetlink_log.h b/include/linux/netfilter/nfnetlink_log.h
--- a/include/linux/netfilter/nfnetlink_log.h
+++ b/include/linux/netfilter/nfnetlink_log.h
@@ -40,8 +40,6 @@ enum nfulnl_attr_type {
NFULA_TIMESTAMP, /* nfulnl_msg_packet_timestamp */
NFULA_IFINDEX_INDEV, /* u_int32_t ifindex */
NFULA_IFINDEX_OUTDEV, /* u_int32_t ifindex */
- NFULA_IFINDEX_PHYSINDEV, /* u_int32_t ifindex */
- NFULA_IFINDEX_PHYSOUTDEV, /* u_int32_t ifindex */
NFULA_HWADDR, /* nfulnl_msg_packet_hw */
NFULA_PAYLOAD, /* opaque data payload */
NFULA_PREFIX, /* string prefix */
diff --git a/include/linux/netfilter/nfnetlink_queue.h b/include/linux/netfilter/nfnetlink_queue.h
--- a/include/linux/netfilter/nfnetlink_queue.h
+++ b/include/linux/netfilter/nfnetlink_queue.h
@@ -36,8 +36,6 @@ enum nfqnl_attr_type {
NFQA_TIMESTAMP, /* nfqnl_msg_packet_timestamp */
NFQA_IFINDEX_INDEV, /* u_int32_t ifindex */
NFQA_IFINDEX_OUTDEV, /* u_int32_t ifindex */
- NFQA_IFINDEX_PHYSINDEV, /* u_int32_t ifindex */
- NFQA_IFINDEX_PHYSOUTDEV, /* u_int32_t ifindex */
NFQA_HWADDR, /* nfqnl_msg_packet_hw */
NFQA_PAYLOAD, /* opaque data payload */
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -33,10 +33,6 @@
#include <asm/atomic.h>
-#ifdef CONFIG_BRIDGE_NETFILTER
-#include "../bridge/br_private.h"
-#endif
-
#define NFULNL_NLBUFSIZ_DEFAULT 4096
#define NFULNL_TIMEOUT_DEFAULT 100 /* every second */
#define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */
@@ -416,64 +412,14 @@ __build_packet_message(struct nfulnl_ins
if (indev) {
tmp_uint = htonl(indev->ifindex);
-#ifndef CONFIG_BRIDGE_NETFILTER
NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint),
&tmp_uint);
-#else
- if (indev->br_port) {
- /* Case 1: indev is physical input device, we need to
- * look for bridge group (when called from
- * netfilter_bridge) */
- NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
- sizeof(tmp_uint), &tmp_uint);
- /* this is the bridge group "brX" */
- tmp_uint = htonl(indev->br_port->br->dev->ifindex);
- NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV,
- sizeof(tmp_uint), &tmp_uint);
- } else {
- /* Case 2: indev is bridge group, we need to look for
- * physical device (when called from ipv4) */
- NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV,
- sizeof(tmp_uint), &tmp_uint);
- if (skb->nf_bridge && skb->nf_bridge->physindev) {
- tmp_uint =
- htonl(skb->nf_bridge->physindev->ifindex);
- NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
- sizeof(tmp_uint), &tmp_uint);
- }
- }
-#endif
}
if (outdev) {
tmp_uint = htonl(outdev->ifindex);
-#ifndef CONFIG_BRIDGE_NETFILTER
NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint),
&tmp_uint);
-#else
- if (outdev->br_port) {
- /* Case 1: outdev is physical output device, we need to
- * look for bridge group (when called from
- * netfilter_bridge) */
- NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
- sizeof(tmp_uint), &tmp_uint);
- /* this is the bridge group "brX" */
- tmp_uint = htonl(outdev->br_port->br->dev->ifindex);
- NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,
- sizeof(tmp_uint), &tmp_uint);
- } else {
- /* Case 2: indev is a bridge group, we need to look
- * for physical device (when called from ipv4) */
- NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,
- sizeof(tmp_uint), &tmp_uint);
- if (skb->nf_bridge) {
- tmp_uint =
- htonl(skb->nf_bridge->physoutdev->ifindex);
- NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
- sizeof(tmp_uint), &tmp_uint);
- }
- }
-#endif
}
if (skb->nfmark) {
@@ -590,10 +536,6 @@ nfulnl_log_packet(unsigned int pf,
+ NFA_SPACE(sizeof(struct nfulnl_msg_packet_hdr))
+ NFA_SPACE(sizeof(u_int32_t)) /* ifindex */
+ NFA_SPACE(sizeof(u_int32_t)) /* ifindex */
-#ifdef CONFIG_BRIDGE_NETFILTER
- + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */
- + NFA_SPACE(sizeof(u_int32_t)) /* ifindex */
-#endif
+ NFA_SPACE(sizeof(u_int32_t)) /* mark */
+ NFA_SPACE(sizeof(u_int32_t)) /* uid */
+ NFA_SPACE(NFULNL_PREFIXLEN) /* prefix */
diff --git a/net/netfilter/nfnetlink_queue.c b/net/netfilter/nfnetlink_queue.c
--- a/net/netfilter/nfnetlink_queue.c
+++ b/net/netfilter/nfnetlink_queue.c
@@ -30,10 +30,6 @@
#include <asm/atomic.h>
-#ifdef CONFIG_BRIDGE_NETFILTER
-#include "../bridge/br_private.h"
-#endif
-
#define NFQNL_QMAX_DEFAULT 1024
#if 0
@@ -365,10 +361,6 @@ nfqnl_build_packet_message(struct nfqnl_
size = NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hdr))
+ NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */
+ NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */
-#ifdef CONFIG_BRIDGE_NETFILTER
- + NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */
- + NLMSG_SPACE(sizeof(u_int32_t)) /* ifindex */
-#endif
+ NLMSG_SPACE(sizeof(u_int32_t)) /* mark */
+ NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_hw))
+ NLMSG_SPACE(sizeof(struct nfqnl_msg_packet_timestamp));
@@ -420,62 +412,12 @@ nfqnl_build_packet_message(struct nfqnl_
if (entry->info->indev) {
tmp_uint = htonl(entry->info->indev->ifindex);
-#ifndef CONFIG_BRIDGE_NETFILTER
NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint), &tmp_uint);
-#else
- if (entry->info->indev->br_port) {
- /* Case 1: indev is physical input device, we need to
- * look for bridge group (when called from
- * netfilter_bridge) */
- NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV, sizeof(tmp_uint),
- &tmp_uint);
- /* this is the bridge group "brX" */
- tmp_uint = htonl(entry->info->indev->br_port->br->dev->ifindex);
- NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint),
- &tmp_uint);
- } else {
- /* Case 2: indev is bridge group, we need to look for
- * physical device (when called from ipv4) */
- NFA_PUT(skb, NFQA_IFINDEX_INDEV, sizeof(tmp_uint),
- &tmp_uint);
- if (entry->skb->nf_bridge
- && entry->skb->nf_bridge->physindev) {
- tmp_uint = htonl(entry->skb->nf_bridge->physindev->ifindex);
- NFA_PUT(skb, NFQA_IFINDEX_PHYSINDEV,
- sizeof(tmp_uint), &tmp_uint);
- }
- }
-#endif
}
if (entry->info->outdev) {
tmp_uint = htonl(entry->info->outdev->ifindex);
-#ifndef CONFIG_BRIDGE_NETFILTER
NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint), &tmp_uint);
-#else
- if (entry->info->outdev->br_port) {
- /* Case 1: outdev is physical output device, we need to
- * look for bridge group (when called from
- * netfilter_bridge) */
- NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV, sizeof(tmp_uint),
- &tmp_uint);
- /* this is the bridge group "brX" */
- tmp_uint = htonl(entry->info->outdev->br_port->br->dev->ifindex);
- NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint),
- &tmp_uint);
- } else {
- /* Case 2: outdev is bridge group, we need to look for
- * physical output device (when called from ipv4) */
- NFA_PUT(skb, NFQA_IFINDEX_OUTDEV, sizeof(tmp_uint),
- &tmp_uint);
- if (entry->skb->nf_bridge
- && entry->skb->nf_bridge->physoutdev) {
- tmp_uint = htonl(entry->skb->nf_bridge->physoutdev->ifindex);
- NFA_PUT(skb, NFQA_IFINDEX_PHYSOUTDEV,
- sizeof(tmp_uint), &tmp_uint);
- }
- }
-#endif
}
if (entry->skb->nfmark) {
[-- Attachment #1.3: nfnetlink_log.c --]
[-- Type: text/plain, Size: 26276 bytes --]
/*
* This is a module which is used for logging packets to userspace via
* nfetlink.
*
* (C) 2005 by Harald Welte <laforge@netfilter.org>
*
* Based on the old ipv4-only ipt_ULOG.c:
* (C) 2000-2004 by Harald Welte <laforge@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/netdevice.h>
#include <linux/netfilter.h>
#include <linux/netlink.h>
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_log.h>
#include <linux/spinlock.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/security.h>
#include <linux/list.h>
#include <linux/jhash.h>
#include <linux/random.h>
#include <net/sock.h>
#include <asm/atomic.h>
#ifdef CONFIG_BRIDGE_NETFILTER
#include "../bridge/br_private.h"
#endif
#define NFULNL_NLBUFSIZ_DEFAULT 4096
#define NFULNL_TIMEOUT_DEFAULT 100 /* every second */
#define NFULNL_QTHRESH_DEFAULT 100 /* 100 packets */
#define PRINTR(x, args...) do { if (net_ratelimit()) \
printk(x, ## args); } while (0);
#if 0
#define UDEBUG(x, args ...) printk(KERN_DEBUG "%s(%d):%s(): " x, \
__FILE__, __LINE__, __FUNCTION__, \
## args)
#else
#define UDEBUG(x, ...)
#endif
struct nfulnl_instance {
struct hlist_node hlist; /* global list of instances */
spinlock_t lock;
atomic_t use; /* use count */
unsigned int qlen; /* number of nlmsgs in skb */
struct sk_buff *skb; /* pre-allocatd skb */
struct nlmsghdr *lastnlh; /* netlink header of last msg in skb */
struct timer_list timer;
int peer_pid; /* PID of the peer process */
/* configurable parameters */
unsigned int flushtimeout; /* timeout until queue flush */
unsigned int nlbufsiz; /* netlink buffer allocation size */
unsigned int qthreshold; /* threshold of the queue */
u_int32_t copy_range;
u_int16_t group_num; /* number of this queue */
u_int8_t copy_mode;
};
static DEFINE_RWLOCK(instances_lock);
#define INSTANCE_BUCKETS 16
static struct hlist_head instance_table[INSTANCE_BUCKETS];
static unsigned int hash_init;
static inline u_int8_t instance_hashfn(u_int16_t group_num)
{
return ((group_num & 0xff) % INSTANCE_BUCKETS);
}
static struct nfulnl_instance *
__instance_lookup(u_int16_t group_num)
{
struct hlist_head *head;
struct hlist_node *pos;
struct nfulnl_instance *inst;
UDEBUG("entering (group_num=%u)\n", group_num);
head = &instance_table[instance_hashfn(group_num)];
hlist_for_each_entry(inst, pos, head, hlist) {
if (inst->group_num == group_num)
return inst;
}
return NULL;
}
static inline void
instance_get(struct nfulnl_instance *inst)
{
atomic_inc(&inst->use);
}
static struct nfulnl_instance *
instance_lookup_get(u_int16_t group_num)
{
struct nfulnl_instance *inst;
read_lock_bh(&instances_lock);
inst = __instance_lookup(group_num);
if (inst)
instance_get(inst);
read_unlock_bh(&instances_lock);
return inst;
}
static void
instance_put(struct nfulnl_instance *inst)
{
if (inst && atomic_dec_and_test(&inst->use)) {
UDEBUG("kfree(inst=%p)\n", inst);
kfree(inst);
}
}
static void nfulnl_timer(unsigned long data);
static struct nfulnl_instance *
instance_create(u_int16_t group_num, int pid)
{
struct nfulnl_instance *inst;
UDEBUG("entering (group_num=%u, pid=%d)\n", group_num,
pid);
write_lock_bh(&instances_lock);
if (__instance_lookup(group_num)) {
inst = NULL;
UDEBUG("aborting, instance already exists\n");
goto out_unlock;
}
inst = kmalloc(sizeof(*inst), GFP_ATOMIC);
if (!inst)
goto out_unlock;
memset(inst, 0, sizeof(*inst));
INIT_HLIST_NODE(&inst->hlist);
inst->lock = SPIN_LOCK_UNLOCKED;
/* needs to be two, since we _put() after creation */
atomic_set(&inst->use, 2);
init_timer(&inst->timer);
inst->timer.function = nfulnl_timer;
inst->timer.data = (unsigned long)inst;
/* don't start timer yet. (re)start it with every packet */
inst->peer_pid = pid;
inst->group_num = group_num;
inst->qthreshold = NFULNL_QTHRESH_DEFAULT;
inst->flushtimeout = NFULNL_TIMEOUT_DEFAULT;
inst->nlbufsiz = NFULNL_NLBUFSIZ_DEFAULT;
inst->copy_mode = NFULNL_COPY_PACKET;
inst->copy_range = 0xffff;
if (!try_module_get(THIS_MODULE))
goto out_free;
hlist_add_head(&inst->hlist,
&instance_table[instance_hashfn(group_num)]);
UDEBUG("newly added node: %p, next=%p\n", &inst->hlist,
inst->hlist.next);
write_unlock_bh(&instances_lock);
return inst;
out_free:
instance_put(inst);
out_unlock:
write_unlock_bh(&instances_lock);
return NULL;
}
static int __nfulnl_send(struct nfulnl_instance *inst);
static void
_instance_destroy2(struct nfulnl_instance *inst, int lock)
{
/* first pull it out of the global list */
if (lock)
write_lock_bh(&instances_lock);
UDEBUG("removing instance %p (queuenum=%u) from hash\n",
inst, inst->group_num);
hlist_del(&inst->hlist);
if (lock)
write_unlock_bh(&instances_lock);
/* then flush all pending packets from skb */
spin_lock_bh(&inst->lock);
if (inst->skb) {
if (inst->qlen)
__nfulnl_send(inst);
if (inst->skb) {
kfree_skb(inst->skb);
inst->skb = NULL;
}
}
spin_unlock_bh(&inst->lock);
/* and finally put the refcount */
instance_put(inst);
module_put(THIS_MODULE);
}
static inline void
__instance_destroy(struct nfulnl_instance *inst)
{
_instance_destroy2(inst, 0);
}
static inline void
instance_destroy(struct nfulnl_instance *inst)
{
_instance_destroy2(inst, 1);
}
static int
nfulnl_set_mode(struct nfulnl_instance *inst, u_int8_t mode,
unsigned int range)
{
int status = 0;
spin_lock_bh(&inst->lock);
switch (mode) {
case NFULNL_COPY_NONE:
case NFULNL_COPY_META:
inst->copy_mode = mode;
inst->copy_range = 0;
break;
case NFULNL_COPY_PACKET:
inst->copy_mode = mode;
/* we're using struct nfattr which has 16bit nfa_len */
if (range > 0xffff)
inst->copy_range = 0xffff;
else
inst->copy_range = range;
break;
default:
status = -EINVAL;
break;
}
spin_unlock_bh(&inst->lock);
return status;
}
static int
nfulnl_set_nlbufsiz(struct nfulnl_instance *inst, u_int32_t nlbufsiz)
{
int status;
spin_lock_bh(&inst->lock);
if (nlbufsiz < NFULNL_NLBUFSIZ_DEFAULT)
status = -ERANGE;
else if (nlbufsiz > 131072)
status = -ERANGE;
else {
inst->nlbufsiz = nlbufsiz;
status = 0;
}
spin_unlock_bh(&inst->lock);
return status;
}
static int
nfulnl_set_timeout(struct nfulnl_instance *inst, u_int32_t timeout)
{
spin_lock_bh(&inst->lock);
inst->flushtimeout = timeout;
spin_unlock_bh(&inst->lock);
return 0;
}
static int
nfulnl_set_qthresh(struct nfulnl_instance *inst, u_int32_t qthresh)
{
spin_lock_bh(&inst->lock);
inst->qthreshold = qthresh;
spin_unlock_bh(&inst->lock);
return 0;
}
static struct sk_buff *nfulnl_alloc_skb(unsigned int inst_size,
unsigned int pkt_size)
{
struct sk_buff *skb;
UDEBUG("entered (%u, %u)\n", inst_size, pkt_size);
/* alloc skb which should be big enough for a whole multipart
* message. WARNING: has to be <= 128k due to slab restrictions */
skb = alloc_skb(inst_size, GFP_ATOMIC);
if (!skb) {
PRINTR("nfnetlink_log: can't alloc whole buffer (%u bytes)\n",
inst_size);
/* try to allocate only as much as we need for current
* packet */
skb = alloc_skb(pkt_size, GFP_ATOMIC);
if (!skb)
PRINTR("nfnetlink_log: can't even alloc %u bytes\n",
pkt_size);
}
return skb;
}
static int
__nfulnl_send(struct nfulnl_instance *inst)
{
int status;
if (timer_pending(&inst->timer))
del_timer(&inst->timer);
if (inst->qlen > 1)
inst->lastnlh->nlmsg_type = NLMSG_DONE;
status = nfnetlink_unicast(inst->skb, inst->peer_pid, MSG_DONTWAIT);
if (status < 0) {
UDEBUG("netlink_unicast() failed\n");
/* FIXME: statistics */
}
inst->qlen = 0;
inst->skb = NULL;
inst->lastnlh = NULL;
return status;
}
static void nfulnl_timer(unsigned long data)
{
struct nfulnl_instance *inst = (struct nfulnl_instance *)data;
UDEBUG("timer function called, flushing buffer\n");
spin_lock_bh(&inst->lock);
__nfulnl_send(inst);
instance_put(inst);
spin_unlock_bh(&inst->lock);
}
static inline int
__build_packet_message(struct nfulnl_instance *inst,
const struct sk_buff *skb,
unsigned int data_len,
unsigned int pf,
unsigned int hooknum,
const struct net_device *indev,
const struct net_device *outdev,
const struct nf_loginfo *li,
const char *prefix)
{
unsigned char *old_tail;
struct nfulnl_msg_packet_hdr pmsg;
struct nlmsghdr *nlh;
struct nfgenmsg *nfmsg;
u_int32_t tmp_uint;
UDEBUG("entered\n");
old_tail = inst->skb->tail;
nlh = NLMSG_PUT(inst->skb, 0, 0,
NFNL_SUBSYS_ULOG << 8 | NFULNL_MSG_PACKET,
sizeof(struct nfgenmsg));
nfmsg = NLMSG_DATA(nlh);
nfmsg->nfgen_family = pf;
nfmsg->version = NFNETLINK_V0;
nfmsg->res_id = htons(inst->group_num);
pmsg.hw_protocol = htons(skb->protocol);
pmsg.hook = hooknum;
NFA_PUT(inst->skb, NFULA_PACKET_HDR, sizeof(pmsg), &pmsg);
if (prefix) {
int slen = strlen(prefix);
if (slen > NFULNL_PREFIXLEN)
slen = NFULNL_PREFIXLEN;
NFA_PUT(inst->skb, NFULA_PREFIX, slen, prefix);
}
if (indev) {
tmp_uint = htonl(indev->ifindex);
#ifndef CONFIG_BRIDGE_NETFILTER
NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV, sizeof(tmp_uint),
&tmp_uint);
#else
if (indev->br_port) {
/* Case 1: indev is physical input device, we need to
* look for bridge group (when called from
* netfilter_bridge) */
NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
sizeof(tmp_uint), &tmp_uint);
/* this is the bridge group "brX" */
tmp_uint = htonl(indev->br_port->br->dev->ifindex);
NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV,
sizeof(tmp_uint), &tmp_uint);
} else {
/* Case 2: indev is bridge group, we need to look for
* physical device (when called from ipv4) */
NFA_PUT(inst->skb, NFULA_IFINDEX_INDEV,
sizeof(tmp_uint), &tmp_uint);
if (skb->nf_bridge && skb->nf_bridge->physindev) {
tmp_uint =
htonl(skb->nf_bridge->physindev->ifindex);
NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
sizeof(tmp_uint), &tmp_uint);
}
}
#endif
}
if (outdev) {
tmp_uint = htonl(outdev->ifindex);
#ifndef CONFIG_BRIDGE_NETFILTER
NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV, sizeof(tmp_uint),
&tmp_uint);
#else
if (outdev->br_port) {
/* Case 1: outdev is physical output device, we need to
* look for bridge group (when called from
* netfilter_bridge) */
NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
sizeof(tmp_uint), &tmp_uint);
/* this is the bridge group "brX" */
tmp_uint = htonl(outdev->br_port->br->dev->ifindex);
NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,
sizeof(tmp_uint), &tmp_uint);
} else {
/* Case 2: indev is a bridge group, we need to look
* for physical device (when called from ipv4) */
NFA_PUT(inst->skb, NFULA_IFINDEX_OUTDEV,
sizeof(tmp_uint), &tmp_uint);
if (skb->nf_bridge) {
tmp_uint =
htonl(skb->nf_bridge->physoutdev->ifindex);
NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSOUTDEV,
sizeof(tmp_uint), &tmp_uint);
}
}
#endif
}
if (skb->nfmark) {
tmp_uint = htonl(skb->nfmark);
NFA_PUT(inst->skb, NFULA_MARK, sizeof(tmp_uint), &tmp_uint);
}
if (indev && skb->dev && skb->dev->hard_header_parse) {
struct nfulnl_msg_packet_hw phw;
phw.hw_addrlen =
skb->dev->hard_header_parse((struct sk_buff *)skb,
phw.hw_addr);
phw.hw_addrlen = htons(phw.hw_addrlen);
NFA_PUT(inst->skb, NFULA_HWADDR, sizeof(phw), &phw);
}
if (skb->stamp.tv_sec) {
struct nfulnl_msg_packet_timestamp ts;
ts.sec = cpu_to_be64(skb->stamp.tv_sec);
ts.usec = cpu_to_be64(skb->stamp.tv_usec);
NFA_PUT(inst->skb, NFULA_TIMESTAMP, sizeof(ts), &ts);
}
/* UID */
if (skb->sk) {
read_lock_bh(&skb->sk->sk_callback_lock);
if (skb->sk->sk_socket && skb->sk->sk_socket->file) {
u_int32_t uid = htonl(skb->sk->sk_socket->file->f_uid);
/* need to unlock here since NFA_PUT may goto */
read_unlock_bh(&skb->sk->sk_callback_lock);
NFA_PUT(inst->skb, NFULA_UID, sizeof(uid), &uid);
} else
read_unlock_bh(&skb->sk->sk_callback_lock);
}
if (data_len) {
struct nfattr *nfa;
int size = NFA_LENGTH(data_len);
if (skb_tailroom(inst->skb) < (int)NFA_SPACE(data_len)) {
printk(KERN_WARNING "nfnetlink_log: no tailroom!\n");
goto nlmsg_failure;
}
nfa = (struct nfattr *)skb_put(inst->skb, NFA_ALIGN(size));
nfa->nfa_type = NFULA_PAYLOAD;
nfa->nfa_len = size;
if (skb_copy_bits(skb, 0, NFA_DATA(nfa), data_len))
BUG();
}
nlh->nlmsg_len = inst->skb->tail - old_tail;
return 0;
nlmsg_failure:
UDEBUG("nlmsg_failure\n");
nfattr_failure:
PRINTR(KERN_ERR "nfnetlink_log: error creating log nlmsg\n");
return -1;
}
#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
static struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_ULOG,
.u = {
.ulog = {
.copy_len = 0xffff,
.group = 0,
.qthreshold = 1,
},
},
};
/* log handler for internal netfilter logging api */
static void
nfulnl_log_packet(unsigned int pf,
unsigned int hooknum,
const struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out,
const struct nf_loginfo *li_user,
const char *prefix)
{
unsigned int size, data_len;
struct nfulnl_instance *inst;
const struct nf_loginfo *li;
unsigned int qthreshold;
unsigned int nlbufsiz;
if (li_user && li_user->type == NF_LOG_TYPE_ULOG)
li = li_user;
else
li = &default_loginfo;
inst = instance_lookup_get(li->u.ulog.group);
if (!inst)
inst = instance_lookup_get(0);
if (!inst) {
PRINTR("nfnetlink_log: trying to log packet, "
"but no instance for group %u\n", li->u.ulog.group);
return;
}
/* all macros expand to constant values at compile time */
/* FIXME: do we want to make the size calculation conditional based on
* what is actually present? way more branches and checks, but more
* memory efficient... */
size = NLMSG_SPACE(sizeof(struct nfgenmsg))
+ NFA_SPACE(sizeof(struct nfulnl_msg_packet_hdr))
+ NFA_SPACE(sizeof(u_int32_t)) /* ifindex */
+ NFA_SPACE(sizeof(u_int32_t)) /* ifindex */
#ifdef CONFIG_BRIDGE_NETFILTER
+ NFA_SPACE(sizeof(u_int32_t)) /* ifindex */
+ NFA_SPACE(sizeof(u_int32_t)) /* ifindex */
#endif
+ NFA_SPACE(sizeof(u_int32_t)) /* mark */
+ NFA_SPACE(sizeof(u_int32_t)) /* uid */
+ NFA_SPACE(NFULNL_PREFIXLEN) /* prefix */
+ NFA_SPACE(sizeof(struct nfulnl_msg_packet_hw))
+ NFA_SPACE(sizeof(struct nfulnl_msg_packet_timestamp));
UDEBUG("initial size=%u\n", size);
spin_lock_bh(&inst->lock);
qthreshold = inst->qthreshold;
/* per-rule qthreshold overrides per-instance */
if (qthreshold > li->u.ulog.qthreshold)
qthreshold = li->u.ulog.qthreshold;
switch (inst->copy_mode) {
case NFULNL_COPY_META:
case NFULNL_COPY_NONE:
data_len = 0;
break;
case NFULNL_COPY_PACKET:
if (inst->copy_range == 0
|| inst->copy_range > skb->len)
data_len = skb->len;
else
data_len = inst->copy_range;
size += NFA_SPACE(data_len);
UDEBUG("copy_packet, therefore size now %u\n", size);
break;
default:
spin_unlock_bh(&inst->lock);
instance_put(inst);
return;
}
if (size > inst->nlbufsiz)
nlbufsiz = size;
else
nlbufsiz = inst->nlbufsiz;
if (!inst->skb) {
if (!(inst->skb = nfulnl_alloc_skb(nlbufsiz, size))) {
UDEBUG("error in nfulnl_alloc_skb(%u, %u)\n",
inst->nlbufsiz, size);
goto alloc_failure;
}
} else if (inst->qlen >= qthreshold ||
size > skb_tailroom(inst->skb)) {
/* either the queue len is too high or we don't have
* enough room in the skb left. flush to userspace. */
UDEBUG("flushing old skb\n");
__nfulnl_send(inst);
if (!(inst->skb = nfulnl_alloc_skb(nlbufsiz, size))) {
UDEBUG("error in nfulnl_alloc_skb(%u, %u)\n",
inst->nlbufsiz, size);
goto alloc_failure;
}
}
UDEBUG("qlen %d, qthreshold %d\n", inst->qlen, qthreshold);
inst->qlen++;
__build_packet_message(inst, skb, data_len, pf,
hooknum, in, out, li, prefix);
/* timer_pending always called within inst->lock, so there
* is no chance of a race here */
if (!timer_pending(&inst->timer)) {
instance_get(inst);
inst->timer.expires = jiffies + (inst->flushtimeout*HZ/100);
add_timer(&inst->timer);
}
spin_unlock_bh(&inst->lock);
return;
alloc_failure:
spin_unlock_bh(&inst->lock);
instance_put(inst);
UDEBUG("error allocating skb\n");
/* FIXME: statistics */
}
static int
nfulnl_rcv_nl_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netlink_notify *n = ptr;
if (event == NETLINK_URELEASE &&
n->protocol == NETLINK_NETFILTER && n->pid) {
int i;
/* destroy all instances for this pid */
write_lock_bh(&instances_lock);
for (i = 0; i < INSTANCE_BUCKETS; i++) {
struct hlist_node *tmp, *t2;
struct nfulnl_instance *inst;
struct hlist_head *head = &instance_table[i];
hlist_for_each_entry_safe(inst, tmp, t2, head, hlist) {
UDEBUG("node = %p\n", inst);
if (n->pid == inst->peer_pid)
__instance_destroy(inst);
}
}
write_unlock_bh(&instances_lock);
}
return NOTIFY_DONE;
}
static struct notifier_block nfulnl_rtnl_notifier = {
.notifier_call = nfulnl_rcv_nl_event,
};
static int
nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *nfqa[], int *errp)
{
return -ENOTSUPP;
}
static struct nf_logger nfulnl_logger = {
.name = "nfnetlink_log",
.logfn = &nfulnl_log_packet,
.me = THIS_MODULE,
};
static const int nfula_min[NFULA_MAX] = {
[NFULA_PACKET_HDR-1] = sizeof(struct nfulnl_msg_packet_hdr),
[NFULA_MARK-1] = sizeof(u_int32_t),
[NFULA_TIMESTAMP-1] = sizeof(struct nfulnl_msg_packet_timestamp),
[NFULA_IFINDEX_INDEV-1] = sizeof(u_int32_t),
[NFULA_IFINDEX_OUTDEV-1]= sizeof(u_int32_t),
[NFULA_HWADDR-1] = sizeof(struct nfulnl_msg_packet_hw),
[NFULA_PAYLOAD-1] = 0,
[NFULA_PREFIX-1] = 0,
[NFULA_UID-1] = sizeof(u_int32_t),
};
static const int nfula_cfg_min[NFULA_CFG_MAX] = {
[NFULA_CFG_CMD-1] = sizeof(struct nfulnl_msg_config_cmd),
[NFULA_CFG_MODE-1] = sizeof(struct nfulnl_msg_config_mode),
[NFULA_CFG_TIMEOUT-1] = sizeof(u_int32_t),
[NFULA_CFG_QTHRESH-1] = sizeof(u_int32_t),
[NFULA_CFG_NLBUFSIZ-1] = sizeof(u_int32_t),
};
static int
nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb,
struct nlmsghdr *nlh, struct nfattr *nfula[], int *errp)
{
struct nfgenmsg *nfmsg = NLMSG_DATA(nlh);
u_int16_t group_num = ntohs(nfmsg->res_id);
struct nfulnl_instance *inst;
int ret = 0;
UDEBUG("entering for msg %u\n", NFNL_MSG_TYPE(nlh->nlmsg_type));
if (nfattr_bad_size(nfula, NFULA_CFG_MAX, nfula_cfg_min)) {
UDEBUG("bad attribute size\n");
return -EINVAL;
}
inst = instance_lookup_get(group_num);
if (nfula[NFULA_CFG_CMD-1]) {
u_int8_t pf = nfmsg->nfgen_family;
struct nfulnl_msg_config_cmd *cmd;
cmd = NFA_DATA(nfula[NFULA_CFG_CMD-1]);
UDEBUG("found CFG_CMD for\n");
switch (cmd->command) {
case NFULNL_CFG_CMD_BIND:
if (inst) {
ret = -EBUSY;
goto out_put;
}
inst = instance_create(group_num,
NETLINK_CB(skb).pid);
if (!inst) {
ret = -EINVAL;
goto out_put;
}
break;
case NFULNL_CFG_CMD_UNBIND:
if (!inst) {
ret = -ENODEV;
goto out_put;
}
if (inst->peer_pid != NETLINK_CB(skb).pid) {
ret = -EPERM;
goto out_put;
}
instance_destroy(inst);
break;
case NFULNL_CFG_CMD_PF_BIND:
UDEBUG("registering log handler for pf=%u\n", pf);
ret = nf_log_register(pf, &nfulnl_logger);
break;
case NFULNL_CFG_CMD_PF_UNBIND:
UDEBUG("unregistering log handler for pf=%u\n", pf);
/* This is a bug and a feature. We cannot unregister
* other handlers, like nfnetlink_inst can */
nf_log_unregister_pf(pf);
break;
default:
ret = -EINVAL;
break;
}
} else {
if (!inst) {
UDEBUG("no config command, and no instance for "
"group=%u pid=%u =>ENOENT\n",
group_num, NETLINK_CB(skb).pid);
ret = -ENOENT;
goto out_put;
}
if (inst->peer_pid != NETLINK_CB(skb).pid) {
UDEBUG("no config command, and wrong pid\n");
ret = -EPERM;
goto out_put;
}
}
if (nfula[NFULA_CFG_MODE-1]) {
struct nfulnl_msg_config_mode *params;
params = NFA_DATA(nfula[NFULA_CFG_MODE-1]);
nfulnl_set_mode(inst, params->copy_mode,
ntohs(params->copy_range));
}
if (nfula[NFULA_CFG_TIMEOUT-1]) {
u_int32_t timeout =
*(u_int32_t *)NFA_DATA(nfula[NFULA_CFG_TIMEOUT-1]);
nfulnl_set_timeout(inst, ntohl(timeout));
}
if (nfula[NFULA_CFG_NLBUFSIZ-1]) {
u_int32_t nlbufsiz =
*(u_int32_t *)NFA_DATA(nfula[NFULA_CFG_NLBUFSIZ-1]);
nfulnl_set_nlbufsiz(inst, ntohl(nlbufsiz));
}
if (nfula[NFULA_CFG_QTHRESH-1]) {
u_int32_t qthresh =
*(u_int16_t *)NFA_DATA(nfula[NFULA_CFG_QTHRESH-1]);
nfulnl_set_qthresh(inst, ntohl(qthresh));
}
out_put:
instance_put(inst);
return ret;
}
static struct nfnl_callback nfulnl_cb[NFULNL_MSG_MAX] = {
[NFULNL_MSG_PACKET] = { .call = nfulnl_recv_unsupp,
.attr_count = NFULA_MAX,
.cap_required = CAP_NET_ADMIN, },
[NFULNL_MSG_CONFIG] = { .call = nfulnl_recv_config,
.attr_count = NFULA_CFG_MAX,
.cap_required = CAP_NET_ADMIN },
};
static struct nfnetlink_subsystem nfulnl_subsys = {
.name = "log",
.subsys_id = NFNL_SUBSYS_ULOG,
.cb_count = NFULNL_MSG_MAX,
.cb = nfulnl_cb,
};
#ifdef CONFIG_PROC_FS
struct iter_state {
unsigned int bucket;
};
static struct hlist_node *get_first(struct seq_file *seq)
{
struct iter_state *st = seq->private;
if (!st)
return NULL;
for (st->bucket = 0; st->bucket < INSTANCE_BUCKETS; st->bucket++) {
if (!hlist_empty(&instance_table[st->bucket]))
return instance_table[st->bucket].first;
}
return NULL;
}
static struct hlist_node *get_next(struct seq_file *seq, struct hlist_node *h)
{
struct iter_state *st = seq->private;
h = h->next;
while (!h) {
if (++st->bucket >= INSTANCE_BUCKETS)
return NULL;
h = instance_table[st->bucket].first;
}
return h;
}
static struct hlist_node *get_idx(struct seq_file *seq, loff_t pos)
{
struct hlist_node *head;
head = get_first(seq);
if (head)
while (pos && (head = get_next(seq, head)))
pos--;
return pos ? NULL : head;
}
static void *seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock_bh(&instances_lock);
return get_idx(seq, *pos);
}
static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
{
(*pos)++;
return get_next(s, v);
}
static void seq_stop(struct seq_file *s, void *v)
{
read_unlock_bh(&instances_lock);
}
static int seq_show(struct seq_file *s, void *v)
{
const struct nfulnl_instance *inst = v;
return seq_printf(s, "%5d %6d %5d %1d %5d %6d %2d\n",
inst->group_num,
inst->peer_pid, inst->qlen,
inst->copy_mode, inst->copy_range,
inst->flushtimeout, atomic_read(&inst->use));
}
static struct seq_operations nful_seq_ops = {
.start = seq_start,
.next = seq_next,
.stop = seq_stop,
.show = seq_show,
};
static int nful_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
struct iter_state *is;
int ret;
is = kmalloc(sizeof(*is), GFP_KERNEL);
if (!is)
return -ENOMEM;
memset(is, 0, sizeof(*is));
ret = seq_open(file, &nful_seq_ops);
if (ret < 0)
goto out_free;
seq = file->private_data;
seq->private = is;
return ret;
out_free:
kfree(is);
return ret;
}
static struct file_operations nful_file_ops = {
.owner = THIS_MODULE,
.open = nful_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
};
#endif /* PROC_FS */
static int
init_or_cleanup(int init)
{
int i, status = -ENOMEM;
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_nful;
#endif
if (!init)
goto cleanup;
for (i = 0; i < INSTANCE_BUCKETS; i++)
INIT_HLIST_HEAD(&instance_table[i]);
/* it's not really all that important to have a random value, so
* we can do this from the init function, even if there hasn't
* been that much entropy yet */
get_random_bytes(&hash_init, sizeof(hash_init));
netlink_register_notifier(&nfulnl_rtnl_notifier);
status = nfnetlink_subsys_register(&nfulnl_subsys);
if (status < 0) {
printk(KERN_ERR "log: failed to create netlink socket\n");
goto cleanup_netlink_notifier;
}
#ifdef CONFIG_PROC_FS
proc_nful = create_proc_entry("nfnetlink_log", 0440,
proc_net_netfilter);
if (!proc_nful)
goto cleanup_subsys;
proc_nful->proc_fops = &nful_file_ops;
#endif
return status;
cleanup:
nf_log_unregister_logger(&nfulnl_logger);
#ifdef CONFIG_PROC_FS
remove_proc_entry("nfnetlink_log", proc_net_netfilter);
cleanup_subsys:
#endif
nfnetlink_subsys_unregister(&nfulnl_subsys);
cleanup_netlink_notifier:
netlink_unregister_notifier(&nfulnl_rtnl_notifier);
return status;
}
static int __init init(void)
{
return init_or_cleanup(1);
}
static void __exit fini(void)
{
init_or_cleanup(0);
}
MODULE_DESCRIPTION("netfilter userspace logging");
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_LICENSE("GPL");
MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG);
module_init(init);
module_exit(fini);
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [RFC PATCH] convert ebt_ulog to nfnetlink_log
From: Bart De Schuymer @ 2005-08-08 6:57 UTC (permalink / raw)
To: Harald Welte; +Cc: Linux Netdev List, Netfilter Development Mailinglist, kaber
In-Reply-To: <20050807213340.GA4508@rama.de.gnumonks.org>
Op zo, 07-08-2005 te 23:33 +0200, schreef Harald Welte:
> > indev->br_port->br->dev->ifindex points to the ifindex of the bridge br0
> > when indev is a bridge port (eth0). So you need this to fill in the
> > input device (assuming we agree that the bridge is called the input
> > device, and the bridge port is called the physical input device).
> > Filling in the physical input device is done with indev (in case
> > indev->br_port is not NULL).
>
> I'm not sure if I can follow you. What basically happens is:
>
> ebt_ulog calls nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, ...) where
> "in" and "out" are struct net_device as passed to the ebt_ulog function
> (which is part of the ebt_watcher).
>
> [...]
>
> the code ends up at the function you are quoting above. "indev"
> is "in" and "outdev" is "out", transparently passed from
> nf_log_packet().
>
> So I think it should reflect exactly what you currently do in ebt_ulog.
> The only diference is that you now get the ifindex and not the device
> name string.
ebt_ulog code snippet:
strcpy(pm->physindev, in->name);
/* If in isn't a bridge, then physindev==indev */
if (in->br_port)
strcpy(pm->indev, in->br_port->br->dev->name);
else
strcpy(pm->indev, in->name);
Your code snippet:
if (indev->br_port) {
tmp_uint = htonl(indev->br_port->br->dev->ifindex);
NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
sizeof(tmp_uint), &tmp_uint);
}
These two code fragments do not do the same thing. If indev is a bridge
port (meaning indev->br_port != NULL), then the NFULA_IFINDEX_PHYSINDEV
must be indev, while the NFULA_IFINDEX_INDEV must be in->br_port->br-
>dev->name.
If indev is not a bridge port, the ebt_ulog code makes
NFULA_IFINDEX_PHYSINDEV and NFULA_IFINDEX_INDEV the same (indev).
cheers,
Bart
^ permalink raw reply
* [PATCH] move conntrack helper buffers out of BSS
From: Harald Welte @ 2005-08-07 22:39 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, Netfilter Development Mailinglist
[-- Attachment #1.1: Type: text/plain, Size: 467 bytes --]
Hi Dave,
I guess you will enjoy the following patch ;)
Please apply to net-2.6.14, thanks.
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #1.2: 36-conntrack_helper-nobss.patch --]
[-- Type: text/plain, Size: 3917 bytes --]
[NETFILTER] move conntrack helper buffers from BSS to kmalloc()ed memory
According to DaveM, it is preferrable to have large data structures be
allocated dynamically from the module init() function rather than putting
them as static global variables into BSS.
This patch moves the conntrack helper packet buffers into dynamically
allocated memory.
Signed-off-by: Harald Welte <laforge@netfilter.org>
---
commit 6a85f7cafea91c2eea692828c7c1602d2da4f4c4
tree 66716ca9e7565377dcd42552a69189c8300f8182
parent 56ca768cb5d27e3b1929656cb186976c3b9af5ec
author Harald Welte <laforge@netfilter.org> Mo, 08 Aug 2005 00:31:23 +0200
committer Harald Welte <laforge@netfilter.org> Mo, 08 Aug 2005 00:31:23 +0200
net/ipv4/netfilter/ip_conntrack_amanda.c | 18 ++++++++++++++++--
net/ipv4/netfilter/ip_conntrack_ftp.c | 9 +++++++--
net/ipv4/netfilter/ip_conntrack_irc.c | 7 ++++++-
3 files changed, 29 insertions(+), 5 deletions(-)
diff --git a/net/ipv4/netfilter/ip_conntrack_amanda.c b/net/ipv4/netfilter/ip_conntrack_amanda.c
--- a/net/ipv4/netfilter/ip_conntrack_amanda.c
+++ b/net/ipv4/netfilter/ip_conntrack_amanda.c
@@ -40,7 +40,7 @@ MODULE_PARM_DESC(master_timeout, "timeou
static char *conns[] = { "DATA ", "MESG ", "INDEX " };
/* This is slow, but it's simple. --RR */
-static char amanda_buffer[65536];
+static char *amanda_buffer;
static DEFINE_SPINLOCK(amanda_buffer_lock);
unsigned int (*ip_nat_amanda_hook)(struct sk_buff **pskb,
@@ -153,11 +153,25 @@ static struct ip_conntrack_helper amanda
static void __exit fini(void)
{
ip_conntrack_helper_unregister(&amanda_helper);
+ kfree(amanda_buffer);
}
static int __init init(void)
{
- return ip_conntrack_helper_register(&amanda_helper);
+ int ret;
+
+ amanda_buffer = kmalloc(65536, GFP_KERNEL);
+ if (!amanda_buffer)
+ return -ENOMEM;
+
+ ret = ip_conntrack_helper_register(&amanda_helper);
+ if (ret < 0) {
+ kfree(amanda_buffer);
+ return ret;
+ }
+ return 0;
+
+
}
module_init(init);
diff --git a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c
@@ -25,8 +25,7 @@ MODULE_AUTHOR("Rusty Russell <rusty@rust
MODULE_DESCRIPTION("ftp connection tracking helper");
/* This is slow, but it's simple. --RR */
-static char ftp_buffer[65536];
-
+static char *ftp_buffer;
static DEFINE_SPINLOCK(ip_ftp_lock);
#define MAX_PORTS 8
@@ -461,6 +460,8 @@ static void fini(void)
ports[i]);
ip_conntrack_helper_unregister(&ftp[i]);
}
+
+ kfree(ftp_buffer);
}
static int __init init(void)
@@ -468,6 +469,10 @@ static int __init init(void)
int i, ret;
char *tmpname;
+ ftp_buffer = kmalloc(65536, GFP_KERNEL);
+ if (!ftp_buffer)
+ return -ENOMEM;
+
if (ports_c == 0)
ports[ports_c++] = FTP_PORT;
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c
@@ -39,7 +39,7 @@ static int ports_c;
static int max_dcc_channels = 8;
static unsigned int dcc_timeout = 300;
/* This is slow, but it's simple. --RR */
-static char irc_buffer[65536];
+static char *irc_buffer;
static DEFINE_SPINLOCK(irc_buffer_lock);
unsigned int (*ip_nat_irc_hook)(struct sk_buff **pskb,
@@ -257,6 +257,10 @@ static int __init init(void)
printk("ip_conntrack_irc: dcc_timeout must be a positive integer\n");
return -EBUSY;
}
+
+ irc_buffer = kmalloc(65536, GFP_KERNEL);
+ if (!irc_buffer)
+ return -ENOMEM;
/* If no port given, default to standard irc port */
if (ports_c == 0)
@@ -304,6 +308,7 @@ static void fini(void)
ports[i]);
ip_conntrack_helper_unregister(&irc_helpers[i]);
}
+ kfree(irc_buffer);
}
module_init(init);
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* [PATCH] split net/core/netfilter.c into net/netfilter/*.c
From: Harald Welte @ 2005-08-07 22:17 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, Netfilter Development Mailinglist
[-- Attachment #1.1: Type: text/plain, Size: 353 bytes --]
Hi Dave,
please apply to net-2.6.14
--
- Harald Welte <laforge@gnumonks.org> http://gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
(ETSI EN 300 175-7 Ch. A6)
[-- Attachment #1.2: 34-netfilter-dirmove.patch --]
[-- Type: text/plain, Size: 43600 bytes --]
[NETFILTER] split net/core/netfilter.c into net/netfilter/*.c
This patch doesn't introduce any code changes, but merely splits the core
netfilter code into four separate files. It also moves it from it's old
location in net/core/ to the recently-created net/netfilter/ directory.
Signed-off-by: Harald Welte <laforge@netfilter.org>
---
commit cfac4409abdf624846d1b97495c4e9c0e4a63658
tree c3b7526dd4aeca3fe6b80e8b0953698881c2ddd8
parent 7e42bac6926c9ab54033ddc4695e9a3d30b6b453
author Harald Welte <laforge@netfilter.org> So, 07 Aug 2005 22:05:00 +0200
committer Harald Welte <laforge@netfilter.org> So, 07 Aug 2005 22:05:00 +0200
net/core/Makefile | 1
net/core/netfilter.c | 737 ------------------------------------------
net/netfilter/Makefile | 4
net/netfilter/core.c | 216 ++++++++++++
net/netfilter/nf_internals.h | 39 ++
net/netfilter/nf_log.c | 165 +++++++++
net/netfilter/nf_queue.c | 273 ++++++++++++++++
net/netfilter/nf_sockopt.c | 132 ++++++++
8 files changed, 829 insertions(+), 738 deletions(-)
diff --git a/net/core/Makefile b/net/core/Makefile
--- a/net/core/Makefile
+++ b/net/core/Makefile
@@ -12,7 +12,6 @@ obj-y += dev.o ethtool.o dev_mcast
obj-$(CONFIG_XFRM) += flow.o
obj-$(CONFIG_SYSFS) += net-sysfs.o
-obj-$(CONFIG_NETFILTER) += netfilter.o
obj-$(CONFIG_NET_DIVERT) += dv.o
obj-$(CONFIG_NET_PKTGEN) += pktgen.o
obj-$(CONFIG_NET_RADIO) += wireless.o
diff --git a/net/core/netfilter.c b/net/core/netfilter.c
deleted file mode 100644
--- a/net/core/netfilter.c
+++ /dev/null
@@ -1,737 +0,0 @@
-/* netfilter.c: look after the filters for various protocols.
- * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
- *
- * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
- * way.
- *
- * Rusty Russell (C)2000 -- This code is GPL.
- *
- * February 2000: Modified by James Morris to have 1 queue per protocol.
- * 15-Mar-2000: Added NF_REPEAT --RR.
- * 08-May-2003: Internal logging interface added by Jozsef Kadlecsik.
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/netfilter.h>
-#include <net/protocol.h>
-#include <linux/init.h>
-#include <linux/skbuff.h>
-#include <linux/wait.h>
-#include <linux/module.h>
-#include <linux/interrupt.h>
-#include <linux/if.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/proc_fs.h>
-#include <net/sock.h>
-
-/* In this code, we can be waiting indefinitely for userspace to
- * service a packet if a hook returns NF_QUEUE. We could keep a count
- * of skbuffs queued for userspace, and not deregister a hook unless
- * this is zero, but that sucks. Now, we simply check when the
- * packets come back: if the hook is gone, the packet is discarded. */
-#ifdef CONFIG_NETFILTER_DEBUG
-#define NFDEBUG(format, args...) printk(format , ## args)
-#else
-#define NFDEBUG(format, args...)
-#endif
-
-/* 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);
-
-struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
-static LIST_HEAD(nf_sockopts);
-static DEFINE_SPINLOCK(nf_hook_lock);
-
-/*
- * A queue handler may be registered for each protocol. Each is protected by
- * long term mutex. The handler must provide an an outfn() to accept packets
- * for queueing and must reinject all packets it receives, no matter what.
- */
-static struct nf_queue_handler_t {
- nf_queue_outfn_t outfn;
- void *data;
-} queue_handler[NPROTO];
-
-static struct nf_queue_rerouter *queue_rerouter;
-
-static DEFINE_RWLOCK(queue_handler_lock);
-
-int nf_register_hook(struct nf_hook_ops *reg)
-{
- struct list_head *i;
-
- spin_lock_bh(&nf_hook_lock);
- list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
- if (reg->priority < ((struct nf_hook_ops *)i)->priority)
- break;
- }
- list_add_rcu(®->list, i->prev);
- spin_unlock_bh(&nf_hook_lock);
-
- synchronize_net();
- return 0;
-}
-
-void nf_unregister_hook(struct nf_hook_ops *reg)
-{
- spin_lock_bh(&nf_hook_lock);
- list_del_rcu(®->list);
- spin_unlock_bh(&nf_hook_lock);
-
- synchronize_net();
-}
-
-/* Do exclusive ranges overlap? */
-static inline int overlap(int min1, int max1, int min2, int max2)
-{
- return max1 > min2 && min1 < max2;
-}
-
-/* Functions to register sockopt ranges (exclusive). */
-int nf_register_sockopt(struct nf_sockopt_ops *reg)
-{
- struct list_head *i;
- int ret = 0;
-
- if (down_interruptible(&nf_sockopt_mutex) != 0)
- return -EINTR;
-
- list_for_each(i, &nf_sockopts) {
- struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
- if (ops->pf == reg->pf
- && (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:
- up(&nf_sockopt_mutex);
- return ret;
-}
-
-void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
-{
- /* No point being interruptible: we're probably in cleanup_module() */
- restart:
- down(&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);
- schedule();
- goto restart;
- }
- list_del(®->list);
- up(&nf_sockopt_mutex);
-}
-
-/* Call get/setsockopt() */
-static int 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 (down_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++;
- up(&nf_sockopt_mutex);
- ret = ops->get(sk, val, opt, len);
- goto out;
- }
- } else {
- if (val >= ops->set_optmin
- && val < ops->set_optmax) {
- ops->use++;
- up(&nf_sockopt_mutex);
- ret = ops->set(sk, val, opt, *len);
- goto out;
- }
- }
- }
- }
- up(&nf_sockopt_mutex);
- return -ENOPROTOOPT;
-
- out:
- down(&nf_sockopt_mutex);
- ops->use--;
- if (ops->cleanup_task)
- wake_up_process(ops->cleanup_task);
- up(&nf_sockopt_mutex);
- return ret;
-}
-
-int nf_setsockopt(struct sock *sk, int pf, int val, char __user *opt,
- int len)
-{
- return nf_sockopt(sk, pf, val, opt, &len, 0);
-}
-
-int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len)
-{
- return nf_sockopt(sk, pf, val, opt, len, 1);
-}
-
-static unsigned int nf_iterate(struct list_head *head,
- struct sk_buff **skb,
- int hook,
- const struct net_device *indev,
- const struct net_device *outdev,
- struct list_head **i,
- int (*okfn)(struct sk_buff *),
- int hook_thresh)
-{
- unsigned int verdict;
-
- /*
- * The caller must not block between calls to this
- * function because of risk of continuing from deleted element.
- */
- list_for_each_continue_rcu(*i, head) {
- struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
-
- if (hook_thresh > elem->priority)
- continue;
-
- /* Optimization: we don't need to hold module
- reference here, since function can't sleep. --RR */
- verdict = elem->hook(hook, skb, indev, outdev, okfn);
- if (verdict != NF_ACCEPT) {
-#ifdef CONFIG_NETFILTER_DEBUG
- if (unlikely((verdict & NF_VERDICT_MASK)
- > NF_MAX_VERDICT)) {
- NFDEBUG("Evil return from %p(%u).\n",
- elem->hook, hook);
- continue;
- }
-#endif
- if (verdict != NF_REPEAT)
- return verdict;
- *i = (*i)->prev;
- }
- }
- return NF_ACCEPT;
-}
-
-int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
-{
- int ret;
-
- if (pf >= NPROTO)
- return -EINVAL;
-
- write_lock_bh(&queue_handler_lock);
- if (queue_handler[pf].outfn)
- ret = -EBUSY;
- else {
- queue_handler[pf].outfn = outfn;
- queue_handler[pf].data = data;
- ret = 0;
- }
- write_unlock_bh(&queue_handler_lock);
-
- return ret;
-}
-
-/* The caller must flush their queue before this */
-int nf_unregister_queue_handler(int pf)
-{
- if (pf >= NPROTO)
- return -EINVAL;
-
- write_lock_bh(&queue_handler_lock);
- queue_handler[pf].outfn = NULL;
- queue_handler[pf].data = NULL;
- write_unlock_bh(&queue_handler_lock);
-
- return 0;
-}
-
-int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
-{
- if (pf >= NPROTO)
- return -EINVAL;
-
- write_lock_bh(&queue_handler_lock);
- memcpy(&queue_rerouter[pf], rer, sizeof(queue_rerouter[pf]));
- write_unlock_bh(&queue_handler_lock);
-
- return 0;
-}
-
-int nf_unregister_queue_rerouter(int pf)
-{
- if (pf >= NPROTO)
- return -EINVAL;
-
- write_lock_bh(&queue_handler_lock);
- memset(&queue_rerouter[pf], 0, sizeof(queue_rerouter[pf]));
- write_unlock_bh(&queue_handler_lock);
- return 0;
-}
-
-void nf_unregister_queue_handlers(nf_queue_outfn_t outfn)
-{
- int pf;
-
- write_lock_bh(&queue_handler_lock);
- for (pf = 0; pf < NPROTO; pf++) {
- if (queue_handler[pf].outfn == outfn) {
- queue_handler[pf].outfn = NULL;
- queue_handler[pf].data = NULL;
- }
- }
- write_unlock_bh(&queue_handler_lock);
-}
-
-/*
- * Any packet that leaves via this function must come back
- * through nf_reinject().
- */
-static int nf_queue(struct sk_buff **skb,
- struct list_head *elem,
- int pf, unsigned int hook,
- struct net_device *indev,
- struct net_device *outdev,
- int (*okfn)(struct sk_buff *),
- unsigned int queuenum)
-{
- int status;
- struct nf_info *info;
-#ifdef CONFIG_BRIDGE_NETFILTER
- struct net_device *physindev = NULL;
- struct net_device *physoutdev = NULL;
-#endif
-
- /* QUEUE == DROP if noone is waiting, to be safe. */
- read_lock(&queue_handler_lock);
- if (!queue_handler[pf].outfn) {
- read_unlock(&queue_handler_lock);
- kfree_skb(*skb);
- return 1;
- }
-
- info = kmalloc(sizeof(*info)+queue_rerouter[pf].rer_size, GFP_ATOMIC);
- if (!info) {
- if (net_ratelimit())
- printk(KERN_ERR "OOM queueing packet %p\n",
- *skb);
- read_unlock(&queue_handler_lock);
- kfree_skb(*skb);
- return 1;
- }
-
- *info = (struct nf_info) {
- (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
-
- /* If it's going away, ignore hook. */
- if (!try_module_get(info->elem->owner)) {
- read_unlock(&queue_handler_lock);
- kfree(info);
- return 0;
- }
-
- /* Bump dev refs so they don't vanish while packet is out */
- if (indev) dev_hold(indev);
- if (outdev) dev_hold(outdev);
-
-#ifdef CONFIG_BRIDGE_NETFILTER
- if ((*skb)->nf_bridge) {
- physindev = (*skb)->nf_bridge->physindev;
- if (physindev) dev_hold(physindev);
- physoutdev = (*skb)->nf_bridge->physoutdev;
- if (physoutdev) dev_hold(physoutdev);
- }
-#endif
- if (queue_rerouter[pf].save)
- queue_rerouter[pf].save(*skb, info);
-
- status = queue_handler[pf].outfn(*skb, info, queuenum,
- queue_handler[pf].data);
-
- if (status >= 0 && queue_rerouter[pf].reroute)
- status = queue_rerouter[pf].reroute(skb, info);
-
- read_unlock(&queue_handler_lock);
-
- if (status < 0) {
- /* James M doesn't say fuck enough. */
- if (indev) dev_put(indev);
- if (outdev) dev_put(outdev);
-#ifdef CONFIG_BRIDGE_NETFILTER
- if (physindev) dev_put(physindev);
- if (physoutdev) dev_put(physoutdev);
-#endif
- module_put(info->elem->owner);
- kfree(info);
- kfree_skb(*skb);
-
- return 1;
- }
-
- return 1;
-}
-
-/* Returns 1 if okfn() needs to be executed by the caller,
- * -EPERM for NF_DROP, 0 otherwise. */
-int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
- struct net_device *indev,
- struct net_device *outdev,
- int (*okfn)(struct sk_buff *),
- int hook_thresh)
-{
- struct list_head *elem;
- unsigned int verdict;
- int ret = 0;
-
- /* We may already have this, but read-locks nest anyway */
- rcu_read_lock();
-
- elem = &nf_hooks[pf][hook];
-next_hook:
- verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
- outdev, &elem, okfn, hook_thresh);
- if (verdict == NF_ACCEPT || verdict == NF_STOP) {
- ret = 1;
- goto unlock;
- } else if (verdict == NF_DROP) {
- kfree_skb(*pskb);
- ret = -EPERM;
- } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
- NFDEBUG("nf_hook: Verdict = QUEUE.\n");
- if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
- verdict >> NF_VERDICT_BITS))
- goto next_hook;
- }
-unlock:
- rcu_read_unlock();
- return ret;
-}
-
-void nf_reinject(struct sk_buff *skb, struct nf_info *info,
- unsigned int verdict)
-{
- struct list_head *elem = &info->elem->list;
- struct list_head *i;
-
- rcu_read_lock();
-
- /* Release those devices we held, or Alexey will kill me. */
- if (info->indev) dev_put(info->indev);
- if (info->outdev) dev_put(info->outdev);
-#ifdef CONFIG_BRIDGE_NETFILTER
- if (skb->nf_bridge) {
- if (skb->nf_bridge->physindev)
- dev_put(skb->nf_bridge->physindev);
- if (skb->nf_bridge->physoutdev)
- dev_put(skb->nf_bridge->physoutdev);
- }
-#endif
-
- /* Drop reference to owner of hook which queued us. */
- module_put(info->elem->owner);
-
- list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
- if (i == elem)
- break;
- }
-
- if (elem == &nf_hooks[info->pf][info->hook]) {
- /* The module which sent it to userspace is gone. */
- NFDEBUG("%s: module disappeared, dropping packet.\n",
- __FUNCTION__);
- verdict = NF_DROP;
- }
-
- /* Continue traversal iff userspace said ok... */
- if (verdict == NF_REPEAT) {
- elem = elem->prev;
- verdict = NF_ACCEPT;
- }
-
- if (verdict == NF_ACCEPT) {
- next_hook:
- verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
- &skb, info->hook,
- info->indev, info->outdev, &elem,
- info->okfn, INT_MIN);
- }
-
- switch (verdict & NF_VERDICT_MASK) {
- case NF_ACCEPT:
- info->okfn(skb);
- break;
-
- case NF_QUEUE:
- if (!nf_queue(&skb, elem, info->pf, info->hook,
- info->indev, info->outdev, info->okfn,
- verdict >> NF_VERDICT_BITS))
- goto next_hook;
- break;
- }
- rcu_read_unlock();
-
- if (verdict == NF_DROP)
- kfree_skb(skb);
-
- kfree(info);
- return;
-}
-
-int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len)
-{
- struct sk_buff *nskb;
-
- if (writable_len > (*pskb)->len)
- return 0;
-
- /* Not exclusive use of packet? Must copy. */
- if (skb_shared(*pskb) || skb_cloned(*pskb))
- goto copy_skb;
-
- return pskb_may_pull(*pskb, writable_len);
-
-copy_skb:
- nskb = skb_copy(*pskb, GFP_ATOMIC);
- if (!nskb)
- return 0;
- BUG_ON(skb_is_nonlinear(nskb));
-
- /* Rest of kernel will get very unhappy if we pass it a
- suddenly-orphaned skbuff */
- if ((*pskb)->sk)
- skb_set_owner_w(nskb, (*pskb)->sk);
- kfree_skb(*pskb);
- *pskb = nskb;
- return 1;
-}
-EXPORT_SYMBOL(skb_make_writable);
-
-/* Internal logging interface, which relies on the real
- LOG target modules */
-
-#define NF_LOG_PREFIXLEN 128
-
-static struct nf_logger *nf_logging[NPROTO]; /* = NULL */
-static DEFINE_SPINLOCK(nf_log_lock);
-
-int nf_log_register(int pf, struct nf_logger *logger)
-{
- int ret = -EBUSY;
-
- /* Any setup of logging members must be done before
- * substituting pointer. */
- spin_lock(&nf_log_lock);
- if (!nf_logging[pf]) {
- rcu_assign_pointer(nf_logging[pf], logger);
- ret = 0;
- }
- spin_unlock(&nf_log_lock);
- return ret;
-}
-
-void nf_log_unregister_pf(int pf)
-{
- spin_lock(&nf_log_lock);
- nf_logging[pf] = NULL;
- spin_unlock(&nf_log_lock);
-
- /* Give time to concurrent readers. */
- synchronize_net();
-}
-
-void nf_log_unregister_logger(struct nf_logger *logger)
-{
- int i;
-
- spin_lock(&nf_log_lock);
- for (i = 0; i < NPROTO; i++) {
- if (nf_logging[i] == logger)
- nf_logging[i] = NULL;
- }
- spin_unlock(&nf_log_lock);
-
- synchronize_net();
-}
-
-void nf_log_packet(int pf,
- unsigned int hooknum,
- const struct sk_buff *skb,
- const struct net_device *in,
- const struct net_device *out,
- struct nf_loginfo *loginfo,
- const char *fmt, ...)
-{
- va_list args;
- char prefix[NF_LOG_PREFIXLEN];
- struct nf_logger *logger;
-
- rcu_read_lock();
- logger = rcu_dereference(nf_logging[pf]);
- if (logger) {
- va_start(args, fmt);
- vsnprintf(prefix, sizeof(prefix), fmt, args);
- va_end(args);
- /* We must read logging before nf_logfn[pf] */
- logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix);
- } else if (net_ratelimit()) {
- printk(KERN_WARNING "nf_log_packet: can\'t log since "
- "no backend logging module loaded in! Please either "
- "load one, or disable logging explicitly\n");
- }
- rcu_read_unlock();
-}
-EXPORT_SYMBOL(nf_log_register);
-EXPORT_SYMBOL(nf_log_unregister_pf);
-EXPORT_SYMBOL(nf_log_unregister_logger);
-EXPORT_SYMBOL(nf_log_packet);
-
-#ifdef CONFIG_PROC_FS
-struct proc_dir_entry *proc_net_netfilter;
-EXPORT_SYMBOL(proc_net_netfilter);
-
-static void *seq_start(struct seq_file *seq, loff_t *pos)
-{
- rcu_read_lock();
-
- if (*pos >= NPROTO)
- return NULL;
-
- return pos;
-}
-
-static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
-{
- (*pos)++;
-
- if (*pos >= NPROTO)
- return NULL;
-
- return pos;
-}
-
-static void seq_stop(struct seq_file *s, void *v)
-{
- rcu_read_unlock();
-}
-
-static int seq_show(struct seq_file *s, void *v)
-{
- loff_t *pos = v;
- const struct nf_logger *logger;
-
- logger = rcu_dereference(nf_logging[*pos]);
-
- if (!logger)
- return seq_printf(s, "%2lld NONE\n", *pos);
-
- return seq_printf(s, "%2lld %s\n", *pos, logger->name);
-}
-
-static struct seq_operations nflog_seq_ops = {
- .start = seq_start,
- .next = seq_next,
- .stop = seq_stop,
- .show = seq_show,
-};
-
-static int nflog_open(struct inode *inode, struct file *file)
-{
- return seq_open(file, &nflog_seq_ops);
-}
-
-static struct file_operations nflog_file_ops = {
- .owner = THIS_MODULE,
- .open = nflog_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = seq_release,
-};
-
-#endif /* PROC_FS */
-
-
-/* This does not belong here, but locally generated errors need it if connection
- tracking in use: without this, connection may not be in hash table, and hence
- manufactured ICMP or RST packets will not be associated with it. */
-void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
-
-void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
-{
- void (*attach)(struct sk_buff *, struct sk_buff *);
-
- if (skb->nfct && (attach = ip_ct_attach) != NULL) {
- mb(); /* Just to be sure: must be read before executing this */
- attach(new, skb);
- }
-}
-
-void __init netfilter_init(void)
-{
- int i, h;
-#ifdef CONFIG_PROC_FS
- struct proc_dir_entry *pde;
-#endif
-
- queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter),
- GFP_KERNEL);
- if (!queue_rerouter)
- panic("netfilter: cannot allocate queue rerouter array\n");
- memset(queue_rerouter, 0, NPROTO * sizeof(struct nf_queue_rerouter));
-
- for (i = 0; i < NPROTO; i++) {
- for (h = 0; h < NF_MAX_HOOKS; h++)
- INIT_LIST_HEAD(&nf_hooks[i][h]);
- }
-
-#ifdef CONFIG_PROC_FS
- proc_net_netfilter = proc_mkdir("netfilter", proc_net);
- if (!proc_net_netfilter)
- panic("cannot create netfilter proc entry");
- pde = create_proc_entry("nf_log", S_IRUGO, proc_net_netfilter);
- if (!pde)
- panic("cannot create /proc/net/netfilter/nf_log");
- pde->proc_fops = &nflog_file_ops;
-#endif
-}
-
-EXPORT_SYMBOL(ip_ct_attach);
-EXPORT_SYMBOL(nf_ct_attach);
-EXPORT_SYMBOL(nf_getsockopt);
-EXPORT_SYMBOL(nf_hook_slow);
-EXPORT_SYMBOL(nf_hooks);
-EXPORT_SYMBOL(nf_register_hook);
-EXPORT_SYMBOL(nf_register_queue_handler);
-EXPORT_SYMBOL(nf_register_sockopt);
-EXPORT_SYMBOL(nf_reinject);
-EXPORT_SYMBOL(nf_setsockopt);
-EXPORT_SYMBOL(nf_unregister_hook);
-EXPORT_SYMBOL(nf_unregister_queue_handler);
-EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
-EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
-EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
-EXPORT_SYMBOL(nf_unregister_sockopt);
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -1,3 +1,7 @@
+netfilter-objs := core.o nf_log.o nf_queue.o nf_sockopt.o
+
+obj-$(CONFIG_NETFILTER) = netfilter.o
+
obj-$(CONFIG_NETFILTER_NETLINK) += nfnetlink.o
obj-$(CONFIG_NETFILTER_NETLINK_QUEUE) += nfnetlink_queue.o
obj-$(CONFIG_NETFILTER_NETLINK_LOG) += nfnetlink_log.o
diff --git a/net/netfilter/core.c b/net/netfilter/core.c
new file mode 100644
--- /dev/null
+++ b/net/netfilter/core.c
@@ -0,0 +1,216 @@
+/* netfilter.c: look after the filters for various protocols.
+ * Heavily influenced by the old firewall.c by David Bonn and Alan Cox.
+ *
+ * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any
+ * way.
+ *
+ * Rusty Russell (C)2000 -- This code is GPL.
+ *
+ * February 2000: Modified by James Morris to have 1 queue per protocol.
+ * 15-Mar-2000: Added NF_REPEAT --RR.
+ * 08-May-2003: Internal logging interface added by Jozsef Kadlecsik.
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/netfilter.h>
+#include <net/protocol.h>
+#include <linux/init.h>
+#include <linux/skbuff.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/proc_fs.h>
+#include <net/sock.h>
+
+#include "nf_internals.h"
+
+/* In this code, we can be waiting indefinitely for userspace to
+ * service a packet if a hook returns NF_QUEUE. We could keep a count
+ * of skbuffs queued for userspace, and not deregister a hook unless
+ * this is zero, but that sucks. Now, we simply check when the
+ * packets come back: if the hook is gone, the packet is discarded. */
+struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
+EXPORT_SYMBOL(nf_hooks);
+static DEFINE_SPINLOCK(nf_hook_lock);
+
+int nf_register_hook(struct nf_hook_ops *reg)
+{
+ struct list_head *i;
+
+ spin_lock_bh(&nf_hook_lock);
+ list_for_each(i, &nf_hooks[reg->pf][reg->hooknum]) {
+ if (reg->priority < ((struct nf_hook_ops *)i)->priority)
+ break;
+ }
+ list_add_rcu(®->list, i->prev);
+ spin_unlock_bh(&nf_hook_lock);
+
+ synchronize_net();
+ return 0;
+}
+EXPORT_SYMBOL(nf_register_hook);
+
+void nf_unregister_hook(struct nf_hook_ops *reg)
+{
+ spin_lock_bh(&nf_hook_lock);
+ list_del_rcu(®->list);
+ spin_unlock_bh(&nf_hook_lock);
+
+ synchronize_net();
+}
+EXPORT_SYMBOL(nf_unregister_hook);
+
+unsigned int nf_iterate(struct list_head *head,
+ struct sk_buff **skb,
+ int hook,
+ const struct net_device *indev,
+ const struct net_device *outdev,
+ struct list_head **i,
+ int (*okfn)(struct sk_buff *),
+ int hook_thresh)
+{
+ unsigned int verdict;
+
+ /*
+ * The caller must not block between calls to this
+ * function because of risk of continuing from deleted element.
+ */
+ list_for_each_continue_rcu(*i, head) {
+ struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
+
+ if (hook_thresh > elem->priority)
+ continue;
+
+ /* Optimization: we don't need to hold module
+ reference here, since function can't sleep. --RR */
+ verdict = elem->hook(hook, skb, indev, outdev, okfn);
+ if (verdict != NF_ACCEPT) {
+#ifdef CONFIG_NETFILTER_DEBUG
+ if (unlikely((verdict & NF_VERDICT_MASK)
+ > NF_MAX_VERDICT)) {
+ NFDEBUG("Evil return from %p(%u).\n",
+ elem->hook, hook);
+ continue;
+ }
+#endif
+ if (verdict != NF_REPEAT)
+ return verdict;
+ *i = (*i)->prev;
+ }
+ }
+ return NF_ACCEPT;
+}
+
+
+/* Returns 1 if okfn() needs to be executed by the caller,
+ * -EPERM for NF_DROP, 0 otherwise. */
+int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
+ struct net_device *indev,
+ struct net_device *outdev,
+ int (*okfn)(struct sk_buff *),
+ int hook_thresh)
+{
+ struct list_head *elem;
+ unsigned int verdict;
+ int ret = 0;
+
+ /* We may already have this, but read-locks nest anyway */
+ rcu_read_lock();
+
+ elem = &nf_hooks[pf][hook];
+next_hook:
+ verdict = nf_iterate(&nf_hooks[pf][hook], pskb, hook, indev,
+ outdev, &elem, okfn, hook_thresh);
+ if (verdict == NF_ACCEPT || verdict == NF_STOP) {
+ ret = 1;
+ goto unlock;
+ } else if (verdict == NF_DROP) {
+ kfree_skb(*pskb);
+ ret = -EPERM;
+ } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
+ NFDEBUG("nf_hook: Verdict = QUEUE.\n");
+ if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
+ verdict >> NF_VERDICT_BITS))
+ goto next_hook;
+ }
+unlock:
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL(nf_hook_slow);
+
+
+int skb_make_writable(struct sk_buff **pskb, unsigned int writable_len)
+{
+ struct sk_buff *nskb;
+
+ if (writable_len > (*pskb)->len)
+ return 0;
+
+ /* Not exclusive use of packet? Must copy. */
+ if (skb_shared(*pskb) || skb_cloned(*pskb))
+ goto copy_skb;
+
+ return pskb_may_pull(*pskb, writable_len);
+
+copy_skb:
+ nskb = skb_copy(*pskb, GFP_ATOMIC);
+ if (!nskb)
+ return 0;
+ BUG_ON(skb_is_nonlinear(nskb));
+
+ /* Rest of kernel will get very unhappy if we pass it a
+ suddenly-orphaned skbuff */
+ if ((*pskb)->sk)
+ skb_set_owner_w(nskb, (*pskb)->sk);
+ kfree_skb(*pskb);
+ *pskb = nskb;
+ return 1;
+}
+EXPORT_SYMBOL(skb_make_writable);
+
+
+/* This does not belong here, but locally generated errors need it if connection
+ tracking in use: without this, connection may not be in hash table, and hence
+ manufactured ICMP or RST packets will not be associated with it. */
+void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
+EXPORT_SYMBOL(ip_ct_attach);
+
+void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
+{
+ void (*attach)(struct sk_buff *, struct sk_buff *);
+
+ if (skb->nfct && (attach = ip_ct_attach) != NULL) {
+ mb(); /* Just to be sure: must be read before executing this */
+ attach(new, skb);
+ }
+}
+EXPORT_SYMBOL(nf_ct_attach);
+
+#ifdef CONFIG_PROC_FS
+struct proc_dir_entry *proc_net_netfilter;
+EXPORT_SYMBOL(proc_net_netfilter);
+#endif
+
+void __init netfilter_init(void)
+{
+ int i, h;
+ for (i = 0; i < NPROTO; i++) {
+ for (h = 0; h < NF_MAX_HOOKS; h++)
+ INIT_LIST_HEAD(&nf_hooks[i][h]);
+ }
+
+#ifdef CONFIG_PROC_FS
+ proc_net_netfilter = proc_mkdir("netfilter", proc_net);
+ if (!proc_net_netfilter)
+ panic("cannot create netfilter proc entry");
+#endif
+
+ if (netfilter_queue_init() < 0)
+ panic("cannot initialize nf_queue");
+ if (netfilter_log_init() < 0)
+ panic("cannot initialize nf_log");
+}
diff --git a/net/netfilter/nf_internals.h b/net/netfilter/nf_internals.h
new file mode 100644
--- /dev/null
+++ b/net/netfilter/nf_internals.h
@@ -0,0 +1,39 @@
+#ifndef _NF_INTERNALS_H
+#define _NF_INTERNALS_H
+
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+
+#ifdef CONFIG_NETFILTER_DEBUG
+#define NFDEBUG(format, args...) printk(format , ## args)
+#else
+#define NFDEBUG(format, args...)
+#endif
+
+
+/* core.c */
+extern unsigned int nf_iterate(struct list_head *head,
+ struct sk_buff **skb,
+ int hook,
+ const struct net_device *indev,
+ const struct net_device *outdev,
+ struct list_head **i,
+ int (*okfn)(struct sk_buff *),
+ int hook_thresh);
+
+/* nf_queue.c */
+extern int nf_queue(struct sk_buff **skb,
+ struct list_head *elem,
+ int pf, unsigned int hook,
+ struct net_device *indev,
+ struct net_device *outdev,
+ int (*okfn)(struct sk_buff *),
+ unsigned int queuenum);
+extern int __init netfilter_queue_init(void);
+
+/* nf_log.c */
+extern int __init netfilter_log_init(void);
+
+#endif
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
new file mode 100644
--- /dev/null
+++ b/net/netfilter/nf_log.c
@@ -0,0 +1,165 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <net/protocol.h>
+
+#include "nf_internals.h"
+
+/* Internal logging interface, which relies on the real
+ LOG target modules */
+
+#define NF_LOG_PREFIXLEN 128
+
+static struct nf_logger *nf_logging[NPROTO]; /* = NULL */
+static DEFINE_SPINLOCK(nf_log_lock);
+
+int nf_log_register(int pf, struct nf_logger *logger)
+{
+ int ret = -EBUSY;
+
+ /* Any setup of logging members must be done before
+ * substituting pointer. */
+ spin_lock(&nf_log_lock);
+ if (!nf_logging[pf]) {
+ rcu_assign_pointer(nf_logging[pf], logger);
+ ret = 0;
+ }
+ spin_unlock(&nf_log_lock);
+ return ret;
+}
+EXPORT_SYMBOL(nf_log_register);
+
+void nf_log_unregister_pf(int pf)
+{
+ spin_lock(&nf_log_lock);
+ nf_logging[pf] = NULL;
+ spin_unlock(&nf_log_lock);
+
+ /* Give time to concurrent readers. */
+ synchronize_net();
+}
+EXPORT_SYMBOL(nf_log_unregister_pf);
+
+void nf_log_unregister_logger(struct nf_logger *logger)
+{
+ int i;
+
+ spin_lock(&nf_log_lock);
+ for (i = 0; i < NPROTO; i++) {
+ if (nf_logging[i] == logger)
+ nf_logging[i] = NULL;
+ }
+ spin_unlock(&nf_log_lock);
+
+ synchronize_net();
+}
+EXPORT_SYMBOL(nf_log_unregister_logger);
+
+void nf_log_packet(int pf,
+ unsigned int hooknum,
+ const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ struct nf_loginfo *loginfo,
+ const char *fmt, ...)
+{
+ va_list args;
+ char prefix[NF_LOG_PREFIXLEN];
+ struct nf_logger *logger;
+
+ rcu_read_lock();
+ logger = rcu_dereference(nf_logging[pf]);
+ if (logger) {
+ va_start(args, fmt);
+ vsnprintf(prefix, sizeof(prefix), fmt, args);
+ va_end(args);
+ /* We must read logging before nf_logfn[pf] */
+ logger->logfn(pf, hooknum, skb, in, out, loginfo, prefix);
+ } else if (net_ratelimit()) {
+ printk(KERN_WARNING "nf_log_packet: can\'t log since "
+ "no backend logging module loaded in! Please either "
+ "load one, or disable logging explicitly\n");
+ }
+ rcu_read_unlock();
+}
+EXPORT_SYMBOL(nf_log_packet);
+
+#ifdef CONFIG_PROC_FS
+static void *seq_start(struct seq_file *seq, loff_t *pos)
+{
+ rcu_read_lock();
+
+ if (*pos >= NPROTO)
+ return NULL;
+
+ return pos;
+}
+
+static void *seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ (*pos)++;
+
+ if (*pos >= NPROTO)
+ return NULL;
+
+ return pos;
+}
+
+static void seq_stop(struct seq_file *s, void *v)
+{
+ rcu_read_unlock();
+}
+
+static int seq_show(struct seq_file *s, void *v)
+{
+ loff_t *pos = v;
+ const struct nf_logger *logger;
+
+ logger = rcu_dereference(nf_logging[*pos]);
+
+ if (!logger)
+ return seq_printf(s, "%2lld NONE\n", *pos);
+
+ return seq_printf(s, "%2lld %s\n", *pos, logger->name);
+}
+
+static struct seq_operations nflog_seq_ops = {
+ .start = seq_start,
+ .next = seq_next,
+ .stop = seq_stop,
+ .show = seq_show,
+};
+
+static int nflog_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &nflog_seq_ops);
+}
+
+static struct file_operations nflog_file_ops = {
+ .owner = THIS_MODULE,
+ .open = nflog_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+#endif /* PROC_FS */
+
+
+int __init netfilter_log_init(void)
+{
+#ifdef CONFIG_PROC_FS
+ struct proc_dir_entry *pde;
+ pde = create_proc_entry("nf_log", S_IRUGO, proc_net_netfilter);
+#endif
+ if (!pde)
+ return -1;
+
+ pde->proc_fops = &nflog_file_ops;
+
+ return 0;
+}
diff --git a/net/netfilter/nf_queue.c b/net/netfilter/nf_queue.c
new file mode 100644
--- /dev/null
+++ b/net/netfilter/nf_queue.c
@@ -0,0 +1,273 @@
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter.h>
+#include <net/protocol.h>
+
+#include "nf_internals.h"
+
+/*
+ * A queue handler may be registered for each protocol. Each is protected by
+ * long term mutex. The handler must provide an an outfn() to accept packets
+ * for queueing and must reinject all packets it receives, no matter what.
+ */
+static struct nf_queue_handler_t {
+ nf_queue_outfn_t outfn;
+ void *data;
+} queue_handler[NPROTO];
+
+static struct nf_queue_rerouter *queue_rerouter;
+
+static DEFINE_RWLOCK(queue_handler_lock);
+
+
+int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
+{
+ int ret;
+
+ if (pf >= NPROTO)
+ return -EINVAL;
+
+ write_lock_bh(&queue_handler_lock);
+ if (queue_handler[pf].outfn)
+ ret = -EBUSY;
+ else {
+ queue_handler[pf].outfn = outfn;
+ queue_handler[pf].data = data;
+ ret = 0;
+ }
+ write_unlock_bh(&queue_handler_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(nf_register_queue_handler);
+
+/* The caller must flush their queue before this */
+int nf_unregister_queue_handler(int pf)
+{
+ if (pf >= NPROTO)
+ return -EINVAL;
+
+ write_lock_bh(&queue_handler_lock);
+ queue_handler[pf].outfn = NULL;
+ queue_handler[pf].data = NULL;
+ write_unlock_bh(&queue_handler_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(nf_unregister_queue_handler);
+
+int nf_register_queue_rerouter(int pf, struct nf_queue_rerouter *rer)
+{
+ if (pf >= NPROTO)
+ return -EINVAL;
+
+ write_lock_bh(&queue_handler_lock);
+ memcpy(&queue_rerouter[pf], rer, sizeof(queue_rerouter[pf]));
+ write_unlock_bh(&queue_handler_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
+
+int nf_unregister_queue_rerouter(int pf)
+{
+ if (pf >= NPROTO)
+ return -EINVAL;
+
+ write_lock_bh(&queue_handler_lock);
+ memset(&queue_rerouter[pf], 0, sizeof(queue_rerouter[pf]));
+ write_unlock_bh(&queue_handler_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
+
+void nf_unregister_queue_handlers(nf_queue_outfn_t outfn)
+{
+ int pf;
+
+ write_lock_bh(&queue_handler_lock);
+ for (pf = 0; pf < NPROTO; pf++) {
+ if (queue_handler[pf].outfn == outfn) {
+ queue_handler[pf].outfn = NULL;
+ queue_handler[pf].data = NULL;
+ }
+ }
+ write_unlock_bh(&queue_handler_lock);
+}
+EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
+
+/*
+ * Any packet that leaves via this function must come back
+ * through nf_reinject().
+ */
+int nf_queue(struct sk_buff **skb,
+ struct list_head *elem,
+ int pf, unsigned int hook,
+ struct net_device *indev,
+ struct net_device *outdev,
+ int (*okfn)(struct sk_buff *),
+ unsigned int queuenum)
+{
+ int status;
+ struct nf_info *info;
+#ifdef CONFIG_BRIDGE_NETFILTER
+ struct net_device *physindev = NULL;
+ struct net_device *physoutdev = NULL;
+#endif
+
+ /* QUEUE == DROP if noone is waiting, to be safe. */
+ read_lock(&queue_handler_lock);
+ if (!queue_handler[pf].outfn) {
+ read_unlock(&queue_handler_lock);
+ kfree_skb(*skb);
+ return 1;
+ }
+
+ info = kmalloc(sizeof(*info)+queue_rerouter[pf].rer_size, GFP_ATOMIC);
+ if (!info) {
+ if (net_ratelimit())
+ printk(KERN_ERR "OOM queueing packet %p\n",
+ *skb);
+ read_unlock(&queue_handler_lock);
+ kfree_skb(*skb);
+ return 1;
+ }
+
+ *info = (struct nf_info) {
+ (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
+
+ /* If it's going away, ignore hook. */
+ if (!try_module_get(info->elem->owner)) {
+ read_unlock(&queue_handler_lock);
+ kfree(info);
+ return 0;
+ }
+
+ /* Bump dev refs so they don't vanish while packet is out */
+ if (indev) dev_hold(indev);
+ if (outdev) dev_hold(outdev);
+
+#ifdef CONFIG_BRIDGE_NETFILTER
+ if ((*skb)->nf_bridge) {
+ physindev = (*skb)->nf_bridge->physindev;
+ if (physindev) dev_hold(physindev);
+ physoutdev = (*skb)->nf_bridge->physoutdev;
+ if (physoutdev) dev_hold(physoutdev);
+ }
+#endif
+ if (queue_rerouter[pf].save)
+ queue_rerouter[pf].save(*skb, info);
+
+ status = queue_handler[pf].outfn(*skb, info, queuenum,
+ queue_handler[pf].data);
+
+ if (status >= 0 && queue_rerouter[pf].reroute)
+ status = queue_rerouter[pf].reroute(skb, info);
+
+ read_unlock(&queue_handler_lock);
+
+ if (status < 0) {
+ /* James M doesn't say fuck enough. */
+ if (indev) dev_put(indev);
+ if (outdev) dev_put(outdev);
+#ifdef CONFIG_BRIDGE_NETFILTER
+ if (physindev) dev_put(physindev);
+ if (physoutdev) dev_put(physoutdev);
+#endif
+ module_put(info->elem->owner);
+ kfree(info);
+ kfree_skb(*skb);
+
+ return 1;
+ }
+
+ return 1;
+}
+
+void nf_reinject(struct sk_buff *skb, struct nf_info *info,
+ unsigned int verdict)
+{
+ struct list_head *elem = &info->elem->list;
+ struct list_head *i;
+
+ rcu_read_lock();
+
+ /* Release those devices we held, or Alexey will kill me. */
+ if (info->indev) dev_put(info->indev);
+ if (info->outdev) dev_put(info->outdev);
+#ifdef CONFIG_BRIDGE_NETFILTER
+ if (skb->nf_bridge) {
+ if (skb->nf_bridge->physindev)
+ dev_put(skb->nf_bridge->physindev);
+ if (skb->nf_bridge->physoutdev)
+ dev_put(skb->nf_bridge->physoutdev);
+ }
+#endif
+
+ /* Drop reference to owner of hook which queued us. */
+ module_put(info->elem->owner);
+
+ list_for_each_rcu(i, &nf_hooks[info->pf][info->hook]) {
+ if (i == elem)
+ break;
+ }
+
+ if (elem == &nf_hooks[info->pf][info->hook]) {
+ /* The module which sent it to userspace is gone. */
+ NFDEBUG("%s: module disappeared, dropping packet.\n",
+ __FUNCTION__);
+ verdict = NF_DROP;
+ }
+
+ /* Continue traversal iff userspace said ok... */
+ if (verdict == NF_REPEAT) {
+ elem = elem->prev;
+ verdict = NF_ACCEPT;
+ }
+
+ if (verdict == NF_ACCEPT) {
+ next_hook:
+ verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
+ &skb, info->hook,
+ info->indev, info->outdev, &elem,
+ info->okfn, INT_MIN);
+ }
+
+ switch (verdict & NF_VERDICT_MASK) {
+ case NF_ACCEPT:
+ info->okfn(skb);
+ break;
+
+ case NF_QUEUE:
+ if (!nf_queue(&skb, elem, info->pf, info->hook,
+ info->indev, info->outdev, info->okfn,
+ verdict >> NF_VERDICT_BITS))
+ goto next_hook;
+ break;
+ }
+ rcu_read_unlock();
+
+ if (verdict == NF_DROP)
+ kfree_skb(skb);
+
+ kfree(info);
+ return;
+}
+EXPORT_SYMBOL(nf_reinject);
+
+int __init netfilter_queue_init(void)
+{
+ queue_rerouter = kmalloc(NPROTO * sizeof(struct nf_queue_rerouter),
+ GFP_KERNEL);
+ if (!queue_rerouter)
+ return -ENOMEM;
+
+ memset(queue_rerouter, 0, NPROTO * sizeof(struct nf_queue_rerouter));
+
+ return 0;
+}
+
diff --git a/net/netfilter/nf_sockopt.c b/net/netfilter/nf_sockopt.c
new file mode 100644
--- /dev/null
+++ b/net/netfilter/nf_sockopt.c
@@ -0,0 +1,132 @@
+#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 <net/sock.h>
+
+#include "nf_internals.h"
+
+/* 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 LIST_HEAD(nf_sockopts);
+
+/* Do exclusive ranges overlap? */
+static inline int overlap(int min1, int max1, int min2, int max2)
+{
+ return max1 > min2 && min1 < max2;
+}
+
+/* Functions to register sockopt ranges (exclusive). */
+int nf_register_sockopt(struct nf_sockopt_ops *reg)
+{
+ struct list_head *i;
+ int ret = 0;
+
+ if (down_interruptible(&nf_sockopt_mutex) != 0)
+ return -EINTR;
+
+ list_for_each(i, &nf_sockopts) {
+ struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i;
+ if (ops->pf == reg->pf
+ && (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:
+ up(&nf_sockopt_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(nf_register_sockopt);
+
+void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
+{
+ /* No point being interruptible: we're probably in cleanup_module() */
+ restart:
+ down(&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);
+ schedule();
+ goto restart;
+ }
+ list_del(®->list);
+ up(&nf_sockopt_mutex);
+}
+EXPORT_SYMBOL(nf_unregister_sockopt);
+
+/* Call get/setsockopt() */
+static int 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 (down_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++;
+ up(&nf_sockopt_mutex);
+ ret = ops->get(sk, val, opt, len);
+ goto out;
+ }
+ } else {
+ if (val >= ops->set_optmin
+ && val < ops->set_optmax) {
+ ops->use++;
+ up(&nf_sockopt_mutex);
+ ret = ops->set(sk, val, opt, *len);
+ goto out;
+ }
+ }
+ }
+ }
+ up(&nf_sockopt_mutex);
+ return -ENOPROTOOPT;
+
+ out:
+ down(&nf_sockopt_mutex);
+ ops->use--;
+ if (ops->cleanup_task)
+ wake_up_process(ops->cleanup_task);
+ up(&nf_sockopt_mutex);
+ return ret;
+}
+
+int nf_setsockopt(struct sock *sk, int pf, int val, char __user *opt,
+ int len)
+{
+ return nf_sockopt(sk, pf, val, opt, &len, 0);
+}
+EXPORT_SYMBOL(nf_setsockopt);
+
+int nf_getsockopt(struct sock *sk, int pf, int val, char __user *opt, int *len)
+{
+ return nf_sockopt(sk, pf, val, opt, len, 1);
+}
+EXPORT_SYMBOL(nf_getsockopt);
+
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* [PATCH] add autoloading support to nfnetlink_log
From: Harald Welte @ 2005-08-07 22:15 UTC (permalink / raw)
To: David Miller; +Cc: Linux Netdev List, Netfilter Development Mailinglist
[-- Attachment #1.1: Type: text/plain, Size: 335 bytes --]
Please apply, thanks
--
- Harald Welte <laforge@gnumonks.org> http://gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
(ETSI EN 300 175-7 Ch. A6)
[-- Attachment #1.2: 33-nfnetlink_log-autoload.patch --]
[-- Type: text/plain, Size: 1022 bytes --]
[NETFILTER] fix autoloading of nfnetlink_log
This patch adds the MODULE_ALIAS required for netnlink autoloading of
nfnetlink_log.
Signed-off-by: Harald Welte <laforge@netfilter.org>
---
commit 7e42bac6926c9ab54033ddc4695e9a3d30b6b453
tree aae33467661ea95482d218e22ceadfa448cc8a0d
parent c16fd4ffed6349d0888cd97a75d04394dac42021
author Harald Welte <laforge@netfilter.org> So, 07 Aug 2005 19:24:43 +0200
committer Harald Welte <laforge@netfilter.org> So, 07 Aug 2005 19:24:43 +0200
net/netfilter/nfnetlink_log.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c
--- a/net/netfilter/nfnetlink_log.c
+++ b/net/netfilter/nfnetlink_log.c
@@ -1013,6 +1013,7 @@ static void __exit fini(void)
MODULE_DESCRIPTION("netfilter userspace logging");
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_LICENSE("GPL");
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_ULOG);
module_init(init);
module_exit(fini);
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [PATCH] add new nfnetlink_log subsystem
From: Thomas Graf @ 2005-08-07 21:55 UTC (permalink / raw)
To: Harald Welte, David Miller, Linux Netdev List,
Netfilter Development Mailinglist
In-Reply-To: <20050807150358.GD4855@rama.de.gnumonks.org>
* Harald Welte <20050807150358.GD4855@rama.de.gnumonks.org> 2005-08-07 17:03
> On Sun, Aug 07, 2005 at 01:20:39PM +0200, Thomas Graf wrote:
> > Same very minor issues as nfnetlink regarding some of the
> > new netlink message construction policies. I'll "fix" them
> > during the conversion to the generic netlink attributes.
>
> is this supposed to happen soon? I also need to update the userspace
> side in case you make any changes, so I'd appreciate any changes going
> in ASAP. Alternatively just tell me what needs to change and I'll
> change it even before the generalization.
Within the next days. It is compatible to the old macros so
as long as we don't delete the old ones userspace can stay
as-is for the moment.
^ permalink raw reply
* Moving... please wait
From: Jeff Garzik @ 2005-08-07 21:51 UTC (permalink / raw)
To: Ravinandan Arakali, linux-ide, netdev, linux-kernel
Cc: raghavendra.koushik, leonid.grossman, rapuru.sriram, akpm
In-Reply-To: <000001c59b91$d7f07370$4810100a@pc.s2io.com>
On Sun, Aug 07, 2005 at 01:51:52PM -0700, Ravinandan Arakali wrote:
> Jeff,
> The entire set of patches have been resent and an additional
> patch13 to address earlier comments.
> Pls confirm if these patches apply correctly.
I'm in the process of moving to a new house, and getting a new computer
lab set up.
I have email and can ACK any critical patches, but everything else must
wait for 2.6.14 to open (which fits nicely into the 2.6 release cycle).
Jeff
^ permalink raw reply
* Re: 2.6.13-rc4-mm1: iptables DROP crashes the computer
From: Espen Fjellvær Olsen @ 2005-08-07 21:40 UTC (permalink / raw)
To: Patrick McHardy; +Cc: netdev, netfilter-devel, linux, discuss, Adrian Bunk
In-Reply-To: <42F65513.3080409@trash.net>
On 07/08/05, Patrick McHardy <kaber@trash.net> wrote:
> Could be related to the refcnt underflow with conntrack event
> notifications enabled. If you have CONFIG_IP_NF_CONNTRACK_EVENTS
> enabled please try this patch.
>
I can confirm that that patch solved my problems, thank you :)
--
Mvh / Best regards
Espen Fjellvær Olsen
espenfjo@gmail.com
Norway
^ permalink raw reply
* Re: [RFC PATCH] convert ebt_ulog to nfnetlink_log
From: Harald Welte @ 2005-08-07 21:33 UTC (permalink / raw)
To: Bart De Schuymer
Cc: Linux Netdev List, Netfilter Development Mailinglist, kaber
In-Reply-To: <1123450076.3378.18.camel@localhost.localdomain>
[-- Attachment #1: Type: text/plain, Size: 2486 bytes --]
On Sun, Aug 07, 2005 at 09:27:56PM +0000, Bart De Schuymer wrote:
> > I really hate to have those CONFIG_BRIDGE_NETFILTER ifdef's all over the
> > code - but for now we have them almost everywhere, so two more doesn't
> > hurt. At some point we need to get rid of this ugliness and have something
> > like an 'input device stack' that can be traversed.
>
> I'm not sure if I understand that, how could this be used to know if
> BRIDGE_NETFILTER was configured?
not at all. It was just my extremely vague idea about something more
generic, like a stack of input devices. Those ifdefs would basically
disappear, and the history of input devices (let's say the individual
decapsulation layers for tunneling, ...) would be visible via some
common structure that could also be used by bridging. You can ignore
that comment/rant, it has no practical relevance in the current
discussion ;)
> > +#ifdef CONFIG_BRIDGE_NETFILTER
> > + if (indev->br_port) {
> > + tmp_uint = htonl(indev->br_port->br->dev->ifindex);
> > + NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
> > + sizeof(tmp_uint), &tmp_uint);
> > + }
>
> indev->br_port->br->dev->ifindex points to the ifindex of the bridge br0
> when indev is a bridge port (eth0). So you need this to fill in the
> input device (assuming we agree that the bridge is called the input
> device, and the bridge port is called the physical input device).
> Filling in the physical input device is done with indev (in case
> indev->br_port is not NULL).
I'm not sure if I can follow you. What basically happens is:
ebt_ulog calls nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, ...) where
"in" and "out" are struct net_device as passed to the ebt_ulog function
(which is part of the ebt_watcher).
[...]
the code ends up at the function you are quoting above. "indev"
is "in" and "outdev" is "out", transparently passed from
nf_log_packet().
So I think it should reflect exactly what you currently do in ebt_ulog.
The only diference is that you now get the ifindex and not the device
name string.
Cheers,
Harald
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: [RFC PATCH] convert ebt_ulog to nfnetlink_log
From: Bart De Schuymer @ 2005-08-07 21:27 UTC (permalink / raw)
To: Harald Welte; +Cc: Linux Netdev List, Netfilter Development Mailinglist, kaber
In-Reply-To: <20050805171028.GA7855@rama.de.gnumonks.org>
Op vr, 05-08-2005 te 19:10 +0200, schreef Harald Welte:
> What about the following (only compile-tested) patch ?
>
> [NETFILTER] add phys{in,out}dev support to nfnetlink_log and nfnetlink_queue
>
> Since bridges don't have a 'reasonable' input and output net_device
> (e.g. 'br0'), we need to add seperate TLV's for the 'physindev' and 'physoutdev'
> to get to the real underlying device (e.g. 'eth0').
>
> I really hate to have those CONFIG_BRIDGE_NETFILTER ifdef's all over the
> code - but for now we have them almost everywhere, so two more doesn't
> hurt. At some point we need to get rid of this ugliness and have something
> like an 'input device stack' that can be traversed.
I'm not sure if I understand that, how could this be used to know if
BRIDGE_NETFILTER was configured?
> +#ifdef CONFIG_BRIDGE_NETFILTER
> + if (indev->br_port) {
> + tmp_uint = htonl(indev->br_port->br->dev->ifindex);
> + NFA_PUT(inst->skb, NFULA_IFINDEX_PHYSINDEV,
> + sizeof(tmp_uint), &tmp_uint);
> + }
indev->br_port->br->dev->ifindex points to the ifindex of the bridge br0
when indev is a bridge port (eth0). So you need this to fill in the
input device (assuming we agree that the bridge is called the input
device, and the bridge port is called the physical input device).
Filling in the physical input device is done with indev (in case
indev->br_port is not NULL).
I can't easily get access to net-2.6.14, so I can't have a full view on
things. If you were to change ebt_ulog, you must also make sure that the
physindev is used for NFULA_IFINDEX_PHYSINDEV. The input_dev member of
the skb will be eth0 if the physindev is known.
Analogous comments hold for the other similar parts of your patch.
cheers,
Bart
^ permalink raw reply
* RE: [PATCH 2.6.12.1 1/12] S2io: Code cleanup
From: Ravinandan Arakali @ 2005-08-07 20:51 UTC (permalink / raw)
To: 'Jeff Garzik', raghavendra.koushik
Cc: netdev, leonid.grossman, rapuru.sriram
In-Reply-To: <42EC5D96.3050304@pobox.com>
Jeff,
The entire set of patches have been resent and an additional
patch13 to address earlier comments.
Pls confirm if these patches apply correctly.
Thanks,
Ravi
-----Original Message-----
From: Jeff Garzik [mailto:jgarzik@pobox.com]
Sent: Saturday, July 30, 2005 10:12 PM
To: raghavendra.koushik@neterion.com
Cc: netdev@oss.sgi.com; ravinandan.arakali@neterion.com;
leonid.grossman@neterion.com; rapuru.sriram@neterion.com
Subject: Re: [PATCH 2.6.12.1 1/12] S2io: Code cleanup
patch doesn't seem to apply :(
Can you please resend the entire series, taking into account the
comments WRT patch #5?
Also, I was unable to include your fixes in my 'fixes' branch, whose
speed to upstream kernel is accelerated, because patch #1 was not bug fixes.
If you want your bug fixes to go upstream as rapidly as possible, make
sure they are ordered before the code cleanups and new features. This
allows me to send the fixes upstream immediately, while allowing further
review and testing of the cleanup/feature patches.
Jeff
^ permalink raw reply
* Re: 2.6.13-rc4-mm1: iptables DROP crashes the computer
From: Patrick McHardy @ 2005-08-07 18:38 UTC (permalink / raw)
To: Adrian Bunk
Cc: Espen Fjellvær Olsen, netfilter-devel, linux, discuss,
netdev
In-Reply-To: <20050807172333.GF3513@stusta.de>
[-- Attachment #1: Type: text/plain, Size: 593 bytes --]
Adrian Bunk wrote:
> On Sun, Aug 07, 2005 at 07:12:00PM +0200, Espen Fjellvær Olsen wrote:
>
>
>>After execing "iptables -A INPUT -j DROP" my computer crashes hard. It
>>dosent hang immediately, but after a couple of seconds.
>>The machine is an amd64, running a clean x86_64 environment.
>>uname -a: Linux gentoo 2.6.13-rc4-mm1 #1 PREEMPT Thu Aug 4 01:01:44
>>CEST 2005 x86_64 AMD Athlon(tm) 64 Processor 3400+ AuthenticAMD
>>...
Could be related to the refcnt underflow with conntrack event
notifications enabled. If you have CONFIG_IP_NF_CONNTRACK_EVENTS
enabled please try this patch.
[-- Attachment #2: x --]
[-- Type: text/plain, Size: 10692 bytes --]
[NETFILTER]: Fix multiple problems with the conntrack event cache
refcnt underflow: the reference count is decremented when a conntrack
entry is removed from the hash but it is not incremented when entering
new entries.
missing protection of process context against softirq context: all
cache operations need to locally disable softirqs to avoid races.
Additionally the event cache can't be initialized when a packet enteres
the conntrack code but needs to be initialized whenever we cache an event
and the stored conntrack entry doesn't match the current one.
incorrect flushing of the event cache in ip_ct_iterate_cleanup: without
real locking we can't flush the cache for different CPUs without incurring
races. The cache for different CPUs can only be flushed when no packets
are going through the code. ip_ct_iterate_cleanup doesn't need to drop
all references, so flushing is moved to the cleanup path.
Signed-off-by: Patrick McHardy <kaber@trash.net>
---
commit d20d18715b8425060334e879ebb4835202457b3e
tree 3279243f59162c14f8ac145473e1c3f4c586b2fa
parent df2e0392536ecdd6385f4319f746045fd6fae38f
author Patrick McHardy <kaber@trash.net> Wed, 03 Aug 2005 20:33:25 +0200
committer Patrick McHardy <kaber@trash.net> Wed, 03 Aug 2005 20:33:25 +0200
include/linux/netfilter_ipv4/ip_conntrack.h | 29 +++---
include/linux/netfilter_ipv4/ip_conntrack_core.h | 14 +--
net/ipv4/netfilter/ip_conntrack_core.c | 107 ++++++++--------------
net/ipv4/netfilter/ip_conntrack_standalone.c | 3 -
4 files changed, 58 insertions(+), 95 deletions(-)
diff --git a/include/linux/netfilter_ipv4/ip_conntrack.h b/include/linux/netfilter_ipv4/ip_conntrack.h
--- a/include/linux/netfilter_ipv4/ip_conntrack.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack.h
@@ -411,6 +411,7 @@ struct ip_conntrack_stat
#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
#include <linux/notifier.h>
+#include <linux/interrupt.h>
struct ip_conntrack_ecache {
struct ip_conntrack *ct;
@@ -445,26 +446,24 @@ ip_conntrack_expect_unregister_notifier(
return notifier_chain_unregister(&ip_conntrack_expect_chain, nb);
}
+extern void ip_ct_deliver_cached_events(const struct ip_conntrack *ct);
+extern void __ip_ct_event_cache_init(struct ip_conntrack *ct);
+
static inline void
ip_conntrack_event_cache(enum ip_conntrack_events event,
const struct sk_buff *skb)
{
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
-
- if (unlikely((struct ip_conntrack *) skb->nfct != ecache->ct)) {
- if (net_ratelimit()) {
- printk(KERN_ERR "ctevent: skb->ct != ecache->ct !!!\n");
- dump_stack();
- }
- }
+ struct ip_conntrack *ct = (struct ip_conntrack *)skb->nfct;
+ struct ip_conntrack_ecache *ecache;
+
+ local_bh_disable();
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
+ if (ct != ecache->ct)
+ __ip_ct_event_cache_init(ct);
ecache->events |= event;
+ local_bh_enable();
}
-extern void
-ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct);
-extern void ip_conntrack_event_cache_init(const struct sk_buff *skb);
-
static inline void ip_conntrack_event(enum ip_conntrack_events event,
struct ip_conntrack *ct)
{
@@ -483,9 +482,7 @@ static inline void ip_conntrack_event_ca
const struct sk_buff *skb) {}
static inline void ip_conntrack_event(enum ip_conntrack_events event,
struct ip_conntrack *ct) {}
-static inline void ip_conntrack_deliver_cached_events_for(
- struct ip_conntrack *ct) {}
-static inline void ip_conntrack_event_cache_init(const struct sk_buff *skb) {}
+static inline void ip_ct_deliver_cached_events(const struct ip_conntrack *ct) {}
static inline void
ip_conntrack_expect_event(enum ip_conntrack_expect_events event,
struct ip_conntrack_expect *exp) {}
diff --git a/include/linux/netfilter_ipv4/ip_conntrack_core.h b/include/linux/netfilter_ipv4/ip_conntrack_core.h
--- a/include/linux/netfilter_ipv4/ip_conntrack_core.h
+++ b/include/linux/netfilter_ipv4/ip_conntrack_core.h
@@ -44,18 +44,14 @@ static inline int ip_conntrack_confirm(s
struct ip_conntrack *ct = (struct ip_conntrack *)(*pskb)->nfct;
int ret = NF_ACCEPT;
- if (ct && !is_confirmed(ct))
- ret = __ip_conntrack_confirm(pskb);
- ip_conntrack_deliver_cached_events_for(ct);
-
+ if (ct) {
+ if (!is_confirmed(ct))
+ ret = __ip_conntrack_confirm(pskb);
+ ip_ct_deliver_cached_events(ct);
+ }
return ret;
}
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
-struct ip_conntrack_ecache;
-extern void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ec);
-#endif
-
extern void __ip_ct_expect_unlink_destroy(struct ip_conntrack_expect *exp);
extern struct list_head *ip_conntrack_hash;
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -85,73 +85,62 @@ struct notifier_block *ip_conntrack_expe
DEFINE_PER_CPU(struct ip_conntrack_ecache, ip_conntrack_ecache);
-static inline void __deliver_cached_events(struct ip_conntrack_ecache *ecache)
+/* deliver cached events and clear cache entry - must be called with locally
+ * disabled softirqs */
+static inline void
+__ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache)
{
+ DEBUGP("ecache: delivering events for %p\n", ecache->ct);
if (is_confirmed(ecache->ct) && !is_dying(ecache->ct) && ecache->events)
notifier_call_chain(&ip_conntrack_chain, ecache->events,
ecache->ct);
ecache->events = 0;
-}
-
-void __ip_ct_deliver_cached_events(struct ip_conntrack_ecache *ecache)
-{
- __deliver_cached_events(ecache);
+ ip_conntrack_put(ecache->ct);
+ ecache->ct = NULL;
}
/* Deliver all cached events for a particular conntrack. This is called
* by code prior to async packet handling or freeing the skb */
-void
-ip_conntrack_deliver_cached_events_for(const struct ip_conntrack *ct)
+void ip_ct_deliver_cached_events(const struct ip_conntrack *ct)
{
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
-
- if (!ct)
- return;
-
- if (ecache->ct == ct) {
- DEBUGP("ecache: delivering event for %p\n", ct);
- __deliver_cached_events(ecache);
- } else {
- if (net_ratelimit())
- printk(KERN_WARNING "ecache: want to deliver for %p, "
- "but cache has %p\n", ct, ecache->ct);
- }
-
- /* signalize that events have already been delivered */
- ecache->ct = NULL;
+ struct ip_conntrack_ecache *ecache;
+
+ local_bh_disable();
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
+ if (ecache->ct == ct)
+ __ip_ct_deliver_cached_events(ecache);
+ local_bh_enable();
}
-/* Deliver cached events for old pending events, if current conntrack != old */
-void ip_conntrack_event_cache_init(const struct sk_buff *skb)
+void __ip_ct_event_cache_init(struct ip_conntrack *ct)
{
- struct ip_conntrack *ct = (struct ip_conntrack *) skb->nfct;
- struct ip_conntrack_ecache *ecache =
- &__get_cpu_var(ip_conntrack_ecache);
+ struct ip_conntrack_ecache *ecache;
/* take care of delivering potentially old events */
- if (ecache->ct != ct) {
- enum ip_conntrack_info ctinfo;
- /* we have to check, since at startup the cache is NULL */
- if (likely(ecache->ct)) {
- DEBUGP("ecache: entered for different conntrack: "
- "ecache->ct=%p, skb->nfct=%p. delivering "
- "events\n", ecache->ct, ct);
- __deliver_cached_events(ecache);
+ ecache = &__get_cpu_var(ip_conntrack_ecache);
+ BUG_ON(ecache->ct == ct);
+ if (ecache->ct)
+ __ip_ct_deliver_cached_events(ecache);
+ /* initialize for this conntrack/packet */
+ ecache->ct = ct;
+ nf_conntrack_get(&ct->ct_general);
+}
+
+/* flush the event cache - touches other CPU's data and must not be called while
+ * packets are still passing through the code */
+static void ip_ct_event_cache_flush(void)
+{
+ struct ip_conntrack_ecache *ecache;
+ int cpu;
+
+ for_each_cpu(cpu) {
+ ecache = &per_cpu(ip_conntrack_ecache, cpu);
+ if (ecache->ct)
ip_conntrack_put(ecache->ct);
- } else {
- DEBUGP("ecache: entered for conntrack %p, "
- "cache was clean before\n", ct);
- }
-
- /* initialize for this conntrack/packet */
- ecache->ct = ip_conntrack_get(skb, &ctinfo);
- /* ecache->events cleared by __deliver_cached_devents() */
- } else {
- DEBUGP("ecache: re-entered for conntrack %p.\n", ct);
}
}
-
+#else
+static inline void ip_ct_event_cache_flush(void) {}
#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
@@ -873,8 +862,6 @@ unsigned int ip_conntrack_in(unsigned in
IP_NF_ASSERT((*pskb)->nfct);
- ip_conntrack_event_cache_init(*pskb);
-
ret = proto->packet(ct, *pskb, ctinfo);
if (ret < 0) {
/* Invalid: inverse of the return code tells
@@ -1273,23 +1260,6 @@ ip_ct_iterate_cleanup(int (*iter)(struct
ip_conntrack_put(ct);
}
-
-#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
- {
- /* we need to deliver all cached events in order to drop
- * the reference counts */
- int cpu;
- for_each_cpu(cpu) {
- struct ip_conntrack_ecache *ecache =
- &per_cpu(ip_conntrack_ecache, cpu);
- if (ecache->ct) {
- __ip_ct_deliver_cached_events(ecache);
- ip_conntrack_put(ecache->ct);
- ecache->ct = NULL;
- }
- }
- }
-#endif
}
/* Fast function for those who don't want to parse /proc (and I don't
@@ -1376,6 +1346,7 @@ void ip_conntrack_flush()
delete... */
synchronize_net();
+ ip_ct_event_cache_flush();
i_see_dead_people:
ip_ct_iterate_cleanup(kill_all, NULL);
if (atomic_read(&ip_conntrack_count) != 0) {
diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c
--- a/net/ipv4/netfilter/ip_conntrack_standalone.c
+++ b/net/ipv4/netfilter/ip_conntrack_standalone.c
@@ -401,7 +401,6 @@ static unsigned int ip_confirm(unsigned
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
- ip_conntrack_event_cache_init(*pskb);
/* We've seen it coming out the other side: confirm it */
return ip_conntrack_confirm(pskb);
}
@@ -419,7 +418,6 @@ static unsigned int ip_conntrack_help(un
ct = ip_conntrack_get(*pskb, &ctinfo);
if (ct && ct->helper) {
unsigned int ret;
- ip_conntrack_event_cache_init(*pskb);
ret = ct->helper->help(pskb, ct, ctinfo);
if (ret != NF_ACCEPT)
return ret;
@@ -978,6 +976,7 @@ EXPORT_SYMBOL_GPL(ip_conntrack_chain);
EXPORT_SYMBOL_GPL(ip_conntrack_expect_chain);
EXPORT_SYMBOL_GPL(ip_conntrack_register_notifier);
EXPORT_SYMBOL_GPL(ip_conntrack_unregister_notifier);
+EXPORT_SYMBOL_GPL(__ip_ct_event_cache_init);
EXPORT_PER_CPU_SYMBOL_GPL(ip_conntrack_ecache);
#endif
EXPORT_SYMBOL(ip_conntrack_protocol_register);
^ permalink raw reply
* Re: 2.6.13-rc4-mm1: iptables DROP crashes the computer
From: Espen Fjellvær Olsen @ 2005-08-07 17:43 UTC (permalink / raw)
To: Adrian Bunk; +Cc: netdev, netfilter-devel, linux, discuss
In-Reply-To: <20050807172333.GF3513@stusta.de>
On 07/08/05, Adrian Bunk <bunk@stusta.de> wrote:
> On Sun, Aug 07, 2005 at 07:12:00PM +0200, Espen Fjellvær Olsen wrote:
>
> > After execing "iptables -A INPUT -j DROP" my computer crashes hard. It
> > dosent hang immediately, but after a couple of seconds.
> > The machine is an amd64, running a clean x86_64 environment.
> > uname -a: Linux gentoo 2.6.13-rc4-mm1 #1 PREEMPT Thu Aug 4 01:01:44
> > CEST 2005 x86_64 AMD Athlon(tm) 64 Processor 3400+ AuthenticAMD
> >...
>
> Is this reproducible or did it happen only once?
It is reproducible, happens each time when running "iptables -A INPUT
-j DROP", other rules like "iptables -A INPUT -m --state
ESTABLISHED,RELATED -p tcp --dport 22 -j ACCEPT" works well tho.
> Are there any messages that might give a hint where to search for the
> problem?
The kernel log dont give any messages before the crash, and since the
computer crash hard i cant check for relevant messages after the crash
;)
> You are reporting this against 2.6.13-rc4-mm1, but are attaching a
> .config of 2.6.13-rc5-mm1. Which kernels are affected, and which are
> not?
Im sorry about that glitch, recently compiled 2.6.13-rc5-mm1, but i
got a kernel panic at boot, havent looked into that yet, but it might
be related to ACPI.
The config for rc4-mm1 and rc5-mm1 is similar.
> Does it still happen if you compile your kernel with preemption
> disabled?
Havent tried this yet, but ill do it right away.
> Please send the output of ./scripts/ver_linux .
If some fields are empty or look unusual you may have an old version.
Compare to the current minimal requirements in Documentation/Changes.
Linux gentoo 2.6.13-rc4-mm1 #1 PREEMPT Thu Aug 4 01:01:44 CEST 2005
x86_64 AMD Athlon(tm) 64 Processor 3400+ AuthenticAMD GNU/Linux
Gnu C 3.4.4
Gnu make 3.80
binutils 2.16.1
util-linux 2.12q
mount 2.12q
module-init-tools 3.2-pre7
e2fsprogs 1.38
reiserfsprogs line
reiser4progs line
xfsprogs 2.6.25
Linux C Library 2.3.5
Dynamic linker (ldd) 2.3.5
Procps 3.2.5
Net-tools 1.60
Kbd 1.12
Sh-utils 5.2.1
udev 065
Modules Loaded iptable_filter ip_tables snd_seq_midi
snd_emu10k1_synth snd_emux_synth snd_seq_virmidi snd_seq_midi_event
snd_seq_midi_emul snd_seq snd_pcm_oss snd_mixer_oss rtc ntfs
snd_emu10k1 snd_rawmidi snd_seq_device snd_ac97_codec snd_pcm
snd_timer snd_page_alloc snd_util_mem snd_hwdep snd soundcore
usb_storage uhci_hcd usbcore
--
Mvh / Best regards
Espen Fjellvær Olsen
espenfjo@gmail.com
Norway
^ permalink raw reply
* Re: 2.6.13-rc4-mm1: iptables DROP crashes the computer
From: Adrian Bunk @ 2005-08-07 17:23 UTC (permalink / raw)
To: Espen Fjellvær Olsen; +Cc: netdev, netfilter-devel, linux, discuss
In-Reply-To: <7aaed09105080710121bba1b5b@mail.gmail.com>
On Sun, Aug 07, 2005 at 07:12:00PM +0200, Espen Fjellvær Olsen wrote:
> After execing "iptables -A INPUT -j DROP" my computer crashes hard. It
> dosent hang immediately, but after a couple of seconds.
> The machine is an amd64, running a clean x86_64 environment.
> uname -a: Linux gentoo 2.6.13-rc4-mm1 #1 PREEMPT Thu Aug 4 01:01:44
> CEST 2005 x86_64 AMD Athlon(tm) 64 Processor 3400+ AuthenticAMD
>...
Is this reproducible or did it happen only once?
Are there any messages that might give a hint where to search for the
problem?
You are reporting this against 2.6.13-rc4-mm1, but are attaching a
.config of 2.6.13-rc5-mm1. Which kernels are affected, and which are
not?
Does it still happen if you compile your kernel with preemption
disabled?
Please send the output of ./scripts/ver_linux .
> Mvh / Best regards
> Espen Fjellvær Olsen
cu
Adrian
--
"Is there not promise of rain?" Ling Tan asked suddenly out
of the darkness. There had been need of rain for many days.
"Only a promise," Lao Er said.
Pearl S. Buck - Dragon Seed
^ permalink raw reply
* RE: {Spam?} {Virus?} Geoff@senson.net (verification)
From: Geoff @ 2005-08-07 16:58 UTC (permalink / raw)
To: netdev
In-Reply-To: <200508071656.j77GucFk015692@host2.lifetimewebsites.com>
[-- Attachment #1: Type: text/plain, Size: 2964 bytes --]
Geoff here,
I'm protecting myself from receiving junk mail.
Just this once, click the link below so I can receive your emails.
You won't have to do this again.
http://spamarrest.com/a2?BGRjBGN1BwchMKExMKMNo3AmYaAanF5wo20j
Spam Arrest - Take control of your inbox!
http://spamarrest.com/affl?910905
------------------------------------------------------------
You are receiving this message in response to your email to
Geoff, a Spam Arrest customer.
Spam Arrest requests that senders verify themselves before
their email is delivered.
When you click the above link, you will be taken to a page
with a graphic on it. Simply read the word in the graphic,
type it into the form, and you're verified.
You will only need to do this once per Spam Arrest customer.
------------------------------------------------------------
Below are the complete headers of the message that this email
was generated in response to.
Return-Path: <netdev@oss.sgi.com>
Received: from host2.lifetimewebsites.com (root@localhost)
by senson.net (8.12.10/8.12.10) with ESMTP id j77Gulna015725
for <geoff@senson.net>; Sun, 7 Aug 2005 12:56:47 -0400
X-ClientAddr: 68.82.191.214
Received: from oss.sgi.com (pcp01494310pcs.tybout01.de.comcast.net [68.82.191.214])
by host2.lifetimewebsites.com (8.12.10/8.12.10) with ESMTP id j77GucFk015692
for <geoff@senson.net>; Sun, 7 Aug 2005 12:56:39 -0400
Message-Id: <200508071656.j77GucFk015692@host2.lifetimewebsites.com>
From: netdev@oss.sgi.com
To: geoff@senson.net
Subject: {Spam?} {Virus?} Geoff@senson.net
Date: Sun, 7 Aug 2005 12:56:48 -0400
MIME-Version: 1.0
Content-Type: multipart/mixed;
boundary="----=_NextPart_000_0002_AB2ECEEE.C24A2913"
X-Priority: 3
X-MSMail-Priority: Normal
X-Mailer: Microsoft Outlook Express 6.00.2600.0000
X-MIMEOLE: Produced By Microsoft MimeOLE V6.00.2600.0000
X-Lifetime-Websites-MailScanner-Information: Please contact Lifetime Websites for more information
X-Lifetime-Websites-MailScanner: Infected with a virus
X-Lifetime-Websites-MailScanner-SpamCheck: spam, SBL+XBL,
SpamAssassin (score=9.799, required 7, FORGED_MUA_OUTLOOK 1.58,
MIME_BASE64_ILLEGAL 1.72, MSGID_FROM_MTA_SHORT 3.31,
NO_REAL_NAME 0.28, RCVD_IN_DYNABLOCK 2.55, RCVD_IN_SORBS 0.10,
UPPERCASE_25_50 0.26)
X-Lifetime-Websites-MailScanner-SpamScore: 9
X-MailScanner-From: netdev@oss.sgi.com
X-Spam-Checker-Version: SpamAssassin 2.63 (2004-01-11) on
host2.lifetimewebsites.com
X-Spam-Level: ****
X-Spam-Status: No, hits=4.5 required=5.0 tests=FORGED_MUA_OUTLOOK,
NO_REAL_NAME,RCVD_IN_DYNABLOCK,RCVD_IN_SORBS autolearn=no version=2.63
Status:
X-SA-Poll-Id: 4083cedb0000492b..1..1123433808000
X-SA-USERIDNR: 900805
Received-SPF: none(oss.sgi.com: oss.sgi.com does not designate permitted sender hosts)
------------------------------------------------------------
Webmasters help stop spam and make 50%.
http://spamarrest.com/affl?910905/affiliates/index.jsp
------------------------------------------------------------
[-- Attachment #2: Type: text/html, Size: 4756 bytes --]
^ permalink raw reply
* Re: [PATCH] add new nfnetlink_log subsystem
From: Harald Welte @ 2005-08-07 15:03 UTC (permalink / raw)
To: Thomas Graf; +Cc: Linux Netdev List, Netfilter Development Mailinglist
In-Reply-To: <20050807112039.GF10481@postel.suug.ch>
[-- Attachment #1: Type: text/plain, Size: 1210 bytes --]
On Sun, Aug 07, 2005 at 01:20:39PM +0200, Thomas Graf wrote:
> * Harald Welte <20050730103005.GB6620@rama.de.gnumonks.org> 2005-07-30 12:30
> > This (long-awaited) patch adds the generic nfnetlink-based userspace
> > logging. nfnetlink_log can be used for any protocol family, and
> > supports upt to 65535 logging groups (that could go to separate logging
> > daemons, e.g.).
>
> Same very minor issues as nfnetlink regarding some of the
> new netlink message construction policies. I'll "fix" them
> during the conversion to the generic netlink attributes.
is this supposed to happen soon? I also need to update the userspace
side in case you make any changes, so I'd appreciate any changes going
in ASAP. Alternatively just tell me what needs to change and I'll
change it even before the generalization.
thanks
--
- Harald Welte <laforge@netfilter.org> http://netfilter.org/
============================================================================
"Fragmentation is like classful addressing -- an interesting early
architectural error that shows how much experimentation was going
on while IP was being designed." -- Paul Vixie
[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]
^ permalink raw reply
* Re: atheros driver - desc
From: Harald Welte @ 2005-08-07 15:01 UTC (permalink / raw)
To: Kalle Valo; +Cc: kernel-mentors, netdev, Jeff Garzik
In-Reply-To: <87pssqp5hk.fsf@litku.valo.iki.fi>
[-- Attachment #1.1: Type: text/plain, Size: 1377 bytes --]
On Sun, Aug 07, 2005 at 10:32:07AM +0300, Kalle Valo wrote:
> Harald Welte <laforge@gnumonks.org> writes:
>
> > I don't want to turn this list into a list of legal discussion, but
> > since I'm heavily dealing with exactly those issues during my
> > gpl-violations.org efforts, I thought I share some of the facts.
>
> Thanks for your answer, it cleared up things. I also don't want to
> discuss legal things here, we can discuss it more privately. But I'll
> just ask one more question in public:
>
> > So in general, at least if you're doing that kind of work within the EU,
> > I wouldn't be worried all that much.
>
> That's good news. But what about inclusion to the official Linux
> kernel? Can a driver reverse-engineered in EU be included to the
> kernel? (Big part of Linux is developed in US, I guess.)
I will consult my legal counsel about this. My current naive position
on this is that only the actuall process of the re-engineering matters,
not the result.
I'll get back as soon as I have a reply from my legal counsel.
--
- Harald Welte <laforge@gnumonks.org> http://gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
(ETSI EN 300 175-7 Ch. A6)
[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 154 bytes --]
_______________________________________________
Kernel-mentors mailing list
Kernel-mentors@selenic.com
http://selenic.com/mailman/listinfo/kernel-mentors
^ permalink raw reply
* Re: [PATCH] add new nfnetlink_log subsystem
From: Thomas Graf @ 2005-08-07 11:20 UTC (permalink / raw)
To: Harald Welte, David Miller, Linux Netdev List,
Netfilter Development Mailinglist
In-Reply-To: <20050730103005.GB6620@rama.de.gnumonks.org>
* Harald Welte <20050730103005.GB6620@rama.de.gnumonks.org> 2005-07-30 12:30
> This (long-awaited) patch adds the generic nfnetlink-based userspace
> logging. nfnetlink_log can be used for any protocol family, and
> supports upt to 65535 logging groups (that could go to separate logging
> daemons, e.g.).
Same very minor issues as nfnetlink regarding some of the
new netlink message construction policies. I'll "fix" them
during the conversion to the generic netlink attributes.
^ permalink raw reply
* Re: atheros driver - desc
From: Kalle Valo @ 2005-08-07 7:32 UTC (permalink / raw)
To: Harald Welte; +Cc: kernel-mentors, netdev, Jeff Garzik
In-Reply-To: <20050806214544.GA4594@rama.de.gnumonks.org>
Harald Welte <laforge@gnumonks.org> writes:
> I don't want to turn this list into a list of legal discussion, but
> since I'm heavily dealing with exactly those issues during my
> gpl-violations.org efforts, I thought I share some of the facts.
Thanks for your answer, it cleared up things. I also don't want to
discuss legal things here, we can discuss it more privately. But I'll
just ask one more question in public:
> So in general, at least if you're doing that kind of work within the EU,
> I wouldn't be worried all that much.
That's good news. But what about inclusion to the official Linux
kernel? Can a driver reverse-engineered in EU be included to the
kernel? (Big part of Linux is developed in US, I guess.)
--
Kalle Valo
^ permalink raw reply
* [PATCH] forcedeth: Initialize link settings in every nv_open()
From: Manfred Spraul @ 2005-08-06 21:47 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Ayaz Abdulla, Netdev, cOzmIc.FI
[-- Attachment #1: Type: text/plain, Size: 622 bytes --]
Rüdiger found a bug in nv_open that explains some of the reports
with duplex mismatches:
nv_open calls nv_update_link_speed for initializing the hardware link speed
registers. If current link setting matches the values in np->linkspeed and
np->duplex, then the function does nothing.
Usually, doing nothing is the right thing, but not in nv_open: During
nv_open, the registers must be initialized because the nic was reset.
The attached patch fixes that by setting np->linkspeed to an invalid value
before calling nv_update_link_speed from nv_open.
Signed-Off-By: Manfred Spraul <manfred@colorfullife.com>
[-- Attachment #2: patch-forcedeth-042-forcelinkinit --]
[-- Type: text/plain, Size: 845 bytes --]
--- 2.6/drivers/net/forcedeth.c 2005-08-06 19:59:56.000000000 +0200
+++ build-2.6/drivers/net/forcedeth.c 2005-08-06 19:59:06.000000000 +0200
@@ -93,6 +93,8 @@
* 0.40: 19 Jul 2005: Add support for mac address change.
* 0.41: 30 Jul 2005: Write back original MAC in nv_close instead
* of nv_remove
+ * 0.42: 06 Aug 2005: Fix lack of link speed initialization
+ * in the second (and later) nv_open call
*
* Known bugs:
* We suspect that on some hardware no TX done interrupts are generated.
@@ -2178,6 +2180,9 @@
writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus);
dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat);
}
+ /* set linkspeed to invalid value, thus force nv_update_linkspeed
+ * to init hw */
+ np->linkspeed = 0;
ret = nv_update_linkspeed(dev);
nv_start_rx(dev);
nv_start_tx(dev);
^ permalink raw reply
* Re: atheros driver - desc
From: Harald Welte @ 2005-08-06 21:45 UTC (permalink / raw)
To: Jeff Garzik; +Cc: Kalle Valo, kernel-mentors, netdev
In-Reply-To: <20050806205308.GA25208@havoc.gtf.org>
[-- Attachment #1.1: Type: text/plain, Size: 2124 bytes --]
On Sat, Aug 06, 2005 at 04:53:08PM -0400, Jeff Garzik wrote:
>
> It is certainly preferred that someone write a document describing the
> hardware, and then a totally separate team write the driver, based on
> that document.
No question to that. However, I think it largely depends on _where_ the
actual re-engineering is done.
Here in Germany, the copyright law is perfectly fine with reverse
engineering, as long as you don't actually decompile. The intent of the
law is to prevent you from gaining access to the source code (which
isn't possible in heavily optimized compiled languages anyway). There
is no problem with trying to learn how the program works and what it
actually does.
All over the EU, the EUCD states that you are explicitly allowed to do
_any_ kind of re-engineering for the purpose of compatibility /
interoperability (and you want to make that card interoperable with
the linux OS...) All you need to do is to ask the copyright holder for
the required documentation. If they don't produce it within a given
timeframe (IIRC one month), then you can go and start re-engineering
without the approval of the copyright holders.
Also, lots of the low-level driver routines are not copyrightable works
anyway. If you need to set up the registers of a device in a certain
sequence in order to get it work, then there is no other way of doing
so. Therefore the corresponding source code is not the result of a
creative process of the author.
I don't want to turn this list into a list of legal discussion, but
since I'm heavily dealing with exactly those issues during my
gpl-violations.org efforts, I thought I share some of the facts.
So in general, at least if you're doing that kind of work within the EU,
I wouldn't be worried all that much.
--
- Harald Welte <laforge@gnumonks.org> http://gnumonks.org/
============================================================================
"Privacy in residential applications is a desirable marketing option."
(ETSI EN 300 175-7 Ch. A6)
[-- Attachment #1.2: Type: application/pgp-signature, Size: 189 bytes --]
[-- Attachment #2: Type: text/plain, Size: 154 bytes --]
_______________________________________________
Kernel-mentors mailing list
Kernel-mentors@selenic.com
http://selenic.com/mailman/listinfo/kernel-mentors
^ permalink raw reply
* Re: atheros driver - desc
From: Mateusz Berezecki @ 2005-08-06 21:38 UTC (permalink / raw)
To: kernel-mentors, netdev; +Cc: Kalle.Valo
In-Reply-To: <8764uig7nm.fsf@litku.valo.iki.fi>
Kalle Valo <Kalle.Valo@iki.fi> wrote:
|
| This is great news. An open source Atheros driver which could be
| included to Linux is really needed.
|
| But how was the reverse engineering done? I noticed that forcedeth
| driver was implemented using the clean room design[1] and Linux
| Broadcom 4301 driver project[2] seems to be using the same method.
Reverse engineering was done by dissassemblying binary HAL
and in harder parts by running it in userspace(yes, that is possible)
and analysing input and produced output. The crucial part was to
discover the meaning of hidden part of the structure describing
device state. Once this was done it will be a little if no problem to me
to provide updates for this driver, unless the whole binary HAL
changes dramatically. That's one of the reasons I do this work myself.
|
| The reason I'm asking this is that I just wouldn't want see the same
| happening this with this driver as happened during reverse engineering
| of pwc Philips Webcam driver (some parts of the driver were removed
| from kernel, but I believe the situation is now solved).
If get into trouble I write documentation :-) I promise.
| Actually, what are requirements to get a reverse engineered driver
| included to Linux? Is clean room design an absolute must? It seems
| that reverse engineering is needed if we want Linux support for most
| of the WLAN cards on the market :(
|
Sad but true. The problem is not at vendors' side though.
Look at FCC regulations... :/
kind regards
Mateusz
^ permalink raw reply
* Re: atheros driver - desc
From: Jeff Garzik @ 2005-08-06 20:53 UTC (permalink / raw)
To: Kalle Valo; +Cc: kernel-mentors, netdev
In-Reply-To: <8764uig7nm.fsf@litku.valo.iki.fi>
It is certainly preferred that someone write a document describing the
hardware, and then a totally separate team write the driver, based on
that document.
Jeff
^ permalink raw reply
* Re: atheros driver - desc
From: Kalle Valo @ 2005-08-06 19:57 UTC (permalink / raw)
To: Mateusz Berezecki; +Cc: kernel-mentors, netdev
In-Reply-To: <42F2D523.9020702@gmail.com>
Mateusz Berezecki <mateuszb@gmail.com> writes:
> The driver is not yet fully working because I didn't finish kernel
> integration yet. Almost all
> driver I/O ops are reverse engineered independently of openbsd openhal
> which is missing just too much.
>
>
> Ok, enough talking. Most of the atheros 5212 hal is now open :)
This is great news. An open source Atheros driver which could be
included to Linux is really needed.
But how was the reverse engineering done? I noticed that forcedeth
driver was implemented using the clean room design[1] and Linux
Broadcom 4301 driver project[2] seems to be using the same method.
The reason I'm asking this is that I just wouldn't want see the same
happening this with this driver as happened during reverse engineering
of pwc Philips Webcam driver (some parts of the driver were removed
from kernel, but I believe the situation is now solved).
Actually, what are requirements to get a reverse engineered driver
included to Linux? Is clean room design an absolute must? It seems
that reverse engineering is needed if we want Linux support for most
of the WLAN cards on the market :(
[1] http://en.wikipedia.org/wiki/Clean_room_design
[2] http://linux-bcom4301.sourceforge.net/go/progress
--
Kalle Valo
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox