Commit 0ab43f84 authored by Harald Welte's avatar Harald Welte Committed by David S. Miller

[NETFILTER]: Core changes required by upcoming nfnetlink_queue code

- split netfiler verdict in 16bit verdict and 16bit queue number
- add 'queuenum' argument to nf_queue_outfn_t and its users ip[6]_queue
- move NFNL_SUBSYS_ definitions from enum to #define
- introduce autoloading for nfnetlink subsystem modules
- add MODULE_ALIAS_NFNL_SUBSYS macro
- add nf_unregister_queue_handlers() to register all handlers for a given
  nf_queue_outfn_t
- add more verbose DEBUGP macro definition to nfnetlink.c
- make nfnetlink_subsys_register fail if subsys already exists
- add some more comments and debug statements to nfnetlink.c
Signed-off-by: default avatarHarald Welte <laforge@netfilter.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2cc7d573
...@@ -21,6 +21,16 @@ ...@@ -21,6 +21,16 @@
#define NF_STOP 5 #define NF_STOP 5
#define NF_MAX_VERDICT NF_STOP #define NF_MAX_VERDICT NF_STOP
/* we overload the higher bits for encoding auxiliary data such as the queue
* number. Not nice, but better than additional function arguments. */
#define NF_VERDICT_MASK 0x0000ffff
#define NF_VERDICT_BITS 16
#define NF_VERDICT_QMASK 0xffff0000
#define NF_VERDICT_QBITS 16
#define NF_QUEUE_NR(x) ((x << NF_VERDICT_QBITS) & NF_VERDICT_QMASK || NF_QUEUE)
/* only for userspace compatibility */ /* only for userspace compatibility */
#ifndef __KERNEL__ #ifndef __KERNEL__
/* Generic cache responses from hook functions. /* Generic cache responses from hook functions.
...@@ -179,10 +189,12 @@ int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt, ...@@ -179,10 +189,12 @@ int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt,
/* Packet queuing */ /* Packet queuing */
typedef int (*nf_queue_outfn_t)(struct sk_buff *skb, typedef int (*nf_queue_outfn_t)(struct sk_buff *skb,
struct nf_info *info, void *data); struct nf_info *info,
unsigned int queuenum, void *data);
extern int nf_register_queue_handler(int pf, extern int nf_register_queue_handler(int pf,
nf_queue_outfn_t outfn, void *data); nf_queue_outfn_t outfn, void *data);
extern int nf_unregister_queue_handler(int pf); extern int nf_unregister_queue_handler(int pf);
extern void nf_unregister_queue_handlers(nf_queue_outfn_t outfn);
extern void nf_reinject(struct sk_buff *skb, extern void nf_reinject(struct sk_buff *skb,
struct nf_info *info, struct nf_info *info,
unsigned int verdict); unsigned int verdict);
......
...@@ -69,15 +69,14 @@ struct nfgenmsg { ...@@ -69,15 +69,14 @@ struct nfgenmsg {
#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) #define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8)
#define NFNL_MSG_TYPE(x) (x & 0x00ff) #define NFNL_MSG_TYPE(x) (x & 0x00ff)
enum nfnl_subsys_id { /* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
NFNL_SUBSYS_NONE = 0, * won't work anymore */
NFNL_SUBSYS_CTNETLINK, #define NFNL_SUBSYS_NONE 0
NFNL_SUBSYS_CTNETLINK_EXP, #define NFNL_SUBSYS_CTNETLINK 1
NFNL_SUBSYS_IPTNETLINK, #define NFNL_SUBSYS_CTNETLINK_EXP 2
NFNL_SUBSYS_QUEUE, #define NFNL_SUBSYS_QUEUE 3
NFNL_SUBSYS_ULOG, #define NFNL_SUBSYS_ULOG 4
NFNL_SUBSYS_COUNT, #define NFNL_SUBSYS_COUNT 5
};
#ifdef __KERNEL__ #ifdef __KERNEL__
...@@ -142,5 +141,8 @@ extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, ...@@ -142,5 +141,8 @@ extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group,
int echo); int echo);
extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _NFNETLINK_H */ #endif /* _NFNETLINK_H */
...@@ -221,7 +221,8 @@ static unsigned int nf_iterate(struct list_head *head, ...@@ -221,7 +221,8 @@ static unsigned int nf_iterate(struct list_head *head,
verdict = elem->hook(hook, skb, indev, outdev, okfn); verdict = elem->hook(hook, skb, indev, outdev, okfn);
if (verdict != NF_ACCEPT) { if (verdict != NF_ACCEPT) {
#ifdef CONFIG_NETFILTER_DEBUG #ifdef CONFIG_NETFILTER_DEBUG
if (unlikely(verdict > NF_MAX_VERDICT)) { if (unlikely((verdict & NF_VERDICT_MASK)
> NF_MAX_VERDICT)) {
NFDEBUG("Evil return from %p(%u).\n", NFDEBUG("Evil return from %p(%u).\n",
elem->hook, hook); elem->hook, hook);
continue; continue;
...@@ -239,6 +240,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) ...@@ -239,6 +240,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
{ {
int ret; int ret;
if (pf >= NPROTO)
return -EINVAL;
write_lock_bh(&queue_handler_lock); write_lock_bh(&queue_handler_lock);
if (queue_handler[pf].outfn) if (queue_handler[pf].outfn)
ret = -EBUSY; ret = -EBUSY;
...@@ -255,6 +259,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) ...@@ -255,6 +259,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
/* The caller must flush their queue before this */ /* The caller must flush their queue before this */
int nf_unregister_queue_handler(int pf) int nf_unregister_queue_handler(int pf)
{ {
if (pf >= NPROTO)
return -EINVAL;
write_lock_bh(&queue_handler_lock); write_lock_bh(&queue_handler_lock);
queue_handler[pf].outfn = NULL; queue_handler[pf].outfn = NULL;
queue_handler[pf].data = NULL; queue_handler[pf].data = NULL;
...@@ -286,6 +293,20 @@ int nf_unregister_queue_rerouter(int pf) ...@@ -286,6 +293,20 @@ int nf_unregister_queue_rerouter(int pf)
return 0; 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 * Any packet that leaves via this function must come back
* through nf_reinject(). * through nf_reinject().
...@@ -295,7 +316,8 @@ static int nf_queue(struct sk_buff **skb, ...@@ -295,7 +316,8 @@ static int nf_queue(struct sk_buff **skb,
int pf, unsigned int hook, int pf, unsigned int hook,
struct net_device *indev, struct net_device *indev,
struct net_device *outdev, struct net_device *outdev,
int (*okfn)(struct sk_buff *)) int (*okfn)(struct sk_buff *),
unsigned int queuenum)
{ {
int status; int status;
struct nf_info *info; struct nf_info *info;
...@@ -347,7 +369,8 @@ static int nf_queue(struct sk_buff **skb, ...@@ -347,7 +369,8 @@ static int nf_queue(struct sk_buff **skb,
if (queue_rerouter[pf].save) if (queue_rerouter[pf].save)
queue_rerouter[pf].save(*skb, info); queue_rerouter[pf].save(*skb, info);
status = queue_handler[pf].outfn(*skb, info, queue_handler[pf].data); status = queue_handler[pf].outfn(*skb, info, queuenum,
queue_handler[pf].data);
if (status >= 0 && queue_rerouter[pf].reroute) if (status >= 0 && queue_rerouter[pf].reroute)
status = queue_rerouter[pf].reroute(skb, info); status = queue_rerouter[pf].reroute(skb, info);
...@@ -397,9 +420,10 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb, ...@@ -397,9 +420,10 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff **pskb,
} else if (verdict == NF_DROP) { } else if (verdict == NF_DROP) {
kfree_skb(*pskb); kfree_skb(*pskb);
ret = -EPERM; ret = -EPERM;
} else if (verdict == NF_QUEUE) { } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
NFDEBUG("nf_hook: Verdict = QUEUE.\n"); NFDEBUG("nf_hook: Verdict = QUEUE.\n");
if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn)) if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
verdict >> NF_VERDICT_BITS))
goto next_hook; goto next_hook;
} }
unlock: unlock:
...@@ -456,14 +480,15 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info, ...@@ -456,14 +480,15 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
info->okfn, INT_MIN); info->okfn, INT_MIN);
} }
switch (verdict) { switch (verdict & NF_VERDICT_MASK) {
case NF_ACCEPT: case NF_ACCEPT:
info->okfn(skb); info->okfn(skb);
break; break;
case NF_QUEUE: case NF_QUEUE:
if (!nf_queue(&skb, elem, info->pf, info->hook, if (!nf_queue(&skb, elem, info->pf, info->hook,
info->indev, info->outdev, info->okfn)) info->indev, info->outdev, info->okfn,
verdict >> NF_VERDICT_BITS))
goto next_hook; goto next_hook;
break; break;
} }
...@@ -613,6 +638,7 @@ EXPORT_SYMBOL(nf_reinject); ...@@ -613,6 +638,7 @@ EXPORT_SYMBOL(nf_reinject);
EXPORT_SYMBOL(nf_setsockopt); EXPORT_SYMBOL(nf_setsockopt);
EXPORT_SYMBOL(nf_unregister_hook); EXPORT_SYMBOL(nf_unregister_hook);
EXPORT_SYMBOL(nf_unregister_queue_handler); EXPORT_SYMBOL(nf_unregister_queue_handler);
EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
EXPORT_SYMBOL_GPL(nf_register_queue_rerouter); EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
EXPORT_SYMBOL(nf_unregister_sockopt); EXPORT_SYMBOL(nf_unregister_sockopt);
...@@ -280,7 +280,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) ...@@ -280,7 +280,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
} }
static int static int
ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
unsigned int queuenum, void *data)
{ {
int status = -EINVAL; int status = -EINVAL;
struct sk_buff *nskb; struct sk_buff *nskb;
......
...@@ -278,7 +278,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp) ...@@ -278,7 +278,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
} }
static int static int
ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
unsigned int queuenum, void *data)
{ {
int status = -EINVAL; int status = -EINVAL;
struct sk_buff *nskb; struct sk_buff *nskb;
......
...@@ -44,7 +44,9 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER); ...@@ -44,7 +44,9 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
static char __initdata nfversion[] = "0.30"; static char __initdata nfversion[] = "0.30";
#if 0 #if 0
#define DEBUGP printk #define DEBUGP(format, args...) \
printk(KERN_DEBUG "%s(%d):%s(): " format, __FILE__, \
__LINE__, __FUNCTION__, ## args)
#else #else
#define DEBUGP(format, args...) #define DEBUGP(format, args...)
#endif #endif
...@@ -67,11 +69,11 @@ int nfnetlink_subsys_register(struct nfnetlink_subsystem *n) ...@@ -67,11 +69,11 @@ int nfnetlink_subsys_register(struct nfnetlink_subsystem *n)
{ {
DEBUGP("registering subsystem ID %u\n", n->subsys_id); DEBUGP("registering subsystem ID %u\n", n->subsys_id);
/* If the netlink socket wasn't created, then fail */
if (!nfnl)
return -1;
nfnl_lock(); nfnl_lock();
if (subsys_table[n->subsys_id]) {
nfnl_unlock();
return -EBUSY;
}
subsys_table[n->subsys_id] = n; subsys_table[n->subsys_id] = n;
nfnl_unlock(); nfnl_unlock();
...@@ -227,8 +229,18 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb, ...@@ -227,8 +229,18 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
type = nlh->nlmsg_type; type = nlh->nlmsg_type;
ss = nfnetlink_get_subsys(type); ss = nfnetlink_get_subsys(type);
if (!ss) if (!ss) {
#ifdef CONFIG_KMOD
/* don't call nfnl_shunlock, since it would reenter
* with further packet processing */
up(&nfnl_sem);
request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
nfnl_shlock();
ss = nfnetlink_get_subsys(type);
if (!ss)
#endif
goto err_inval; goto err_inval;
}
nc = nfnetlink_find_client(type, ss); nc = nfnetlink_find_client(type, ss);
if (!nc) { if (!nc) {
...@@ -252,12 +264,14 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb, ...@@ -252,12 +264,14 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
if (err < 0) if (err < 0)
goto err_inval; goto err_inval;
DEBUGP("calling handler\n");
err = nc->call(nfnl, skb, nlh, cda, errp); err = nc->call(nfnl, skb, nlh, cda, errp);
*errp = err; *errp = err;
return err; return err;
} }
err_inval: err_inval:
DEBUGP("returning -EINVAL\n");
*errp = -EINVAL; *errp = -EINVAL;
return -1; return -1;
} }
...@@ -311,6 +325,8 @@ static void nfnetlink_rcv(struct sock *sk, int len) ...@@ -311,6 +325,8 @@ static void nfnetlink_rcv(struct sock *sk, int len)
kfree_skb(skb); kfree_skb(skb);
} }
/* don't call nfnl_shunlock, since it would reenter
* with further packet processing */
up(&nfnl_sem); up(&nfnl_sem);
} while(nfnl && nfnl->sk_receive_queue.qlen); } while(nfnl && nfnl->sk_receive_queue.qlen);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment