aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@netfilter.org>2005-08-09 22:43:44 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2005-08-29 18:36:49 -0400
commit0ab43f84995f2c2fcc5cc58a9accaa1095e1317f (patch)
treef58711648f91bbd880fcada7718a2462f0249a78
parent2cc7d5730957c4a3f3659d17d2ba5e06d5581c1f (diff)
[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: Harald Welte <laforge@netfilter.org> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/netfilter.h14
-rw-r--r--include/linux/netfilter/nfnetlink.h20
-rw-r--r--net/core/netfilter.c40
-rw-r--r--net/ipv4/netfilter/ip_queue.c3
-rw-r--r--net/ipv6/netfilter/ip6_queue.c3
-rw-r--r--net/netfilter/nfnetlink.c28
6 files changed, 83 insertions, 25 deletions
diff --git a/include/linux/netfilter.h b/include/linux/netfilter.h
index d163e20ca8d9..711e05f33d68 100644
--- a/include/linux/netfilter.h
+++ b/include/linux/netfilter.h
@@ -21,6 +21,16 @@
21#define NF_STOP 5 21#define NF_STOP 5
22#define NF_MAX_VERDICT NF_STOP 22#define NF_MAX_VERDICT NF_STOP
23 23
24/* we overload the higher bits for encoding auxiliary data such as the queue
25 * number. Not nice, but better than additional function arguments. */
26#define NF_VERDICT_MASK 0x0000ffff
27#define NF_VERDICT_BITS 16
28
29#define NF_VERDICT_QMASK 0xffff0000
30#define NF_VERDICT_QBITS 16
31
32#define NF_QUEUE_NR(x) ((x << NF_VERDICT_QBITS) & NF_VERDICT_QMASK || NF_QUEUE)
33
24/* only for userspace compatibility */ 34/* only for userspace compatibility */
25#ifndef __KERNEL__ 35#ifndef __KERNEL__
26/* Generic cache responses from hook functions. 36/* Generic cache responses from hook functions.
@@ -179,10 +189,12 @@ int nf_getsockopt(struct sock *sk, int pf, int optval, char __user *opt,
179 189
180/* Packet queuing */ 190/* Packet queuing */
181typedef int (*nf_queue_outfn_t)(struct sk_buff *skb, 191typedef int (*nf_queue_outfn_t)(struct sk_buff *skb,
182 struct nf_info *info, void *data); 192 struct nf_info *info,
193 unsigned int queuenum, void *data);
183extern int nf_register_queue_handler(int pf, 194extern int nf_register_queue_handler(int pf,
184 nf_queue_outfn_t outfn, void *data); 195 nf_queue_outfn_t outfn, void *data);
185extern int nf_unregister_queue_handler(int pf); 196extern int nf_unregister_queue_handler(int pf);
197extern void nf_unregister_queue_handlers(nf_queue_outfn_t outfn);
186extern void nf_reinject(struct sk_buff *skb, 198extern void nf_reinject(struct sk_buff *skb,
187 struct nf_info *info, 199 struct nf_info *info,
188 unsigned int verdict); 200 unsigned int verdict);
diff --git a/include/linux/netfilter/nfnetlink.h b/include/linux/netfilter/nfnetlink.h
index ace7a7be0742..561f9df28808 100644
--- a/include/linux/netfilter/nfnetlink.h
+++ b/include/linux/netfilter/nfnetlink.h
@@ -69,15 +69,14 @@ struct nfgenmsg {
69#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8) 69#define NFNL_SUBSYS_ID(x) ((x & 0xff00) >> 8)
70#define NFNL_MSG_TYPE(x) (x & 0x00ff) 70#define NFNL_MSG_TYPE(x) (x & 0x00ff)
71 71
72enum nfnl_subsys_id { 72/* No enum here, otherwise __stringify() trick of MODULE_ALIAS_NFNL_SUBSYS()
73 NFNL_SUBSYS_NONE = 0, 73 * won't work anymore */
74 NFNL_SUBSYS_CTNETLINK, 74#define NFNL_SUBSYS_NONE 0
75 NFNL_SUBSYS_CTNETLINK_EXP, 75#define NFNL_SUBSYS_CTNETLINK 1
76 NFNL_SUBSYS_IPTNETLINK, 76#define NFNL_SUBSYS_CTNETLINK_EXP 2
77 NFNL_SUBSYS_QUEUE, 77#define NFNL_SUBSYS_QUEUE 3
78 NFNL_SUBSYS_ULOG, 78#define NFNL_SUBSYS_ULOG 4
79 NFNL_SUBSYS_COUNT, 79#define NFNL_SUBSYS_COUNT 5
80};
81 80
82#ifdef __KERNEL__ 81#ifdef __KERNEL__
83 82
@@ -142,5 +141,8 @@ extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group,
142 int echo); 141 int echo);
143extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); 142extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags);
144 143
144#define MODULE_ALIAS_NFNL_SUBSYS(subsys) \
145 MODULE_ALIAS("nfnetlink-subsys-" __stringify(subsys))
146
145#endif /* __KERNEL__ */ 147#endif /* __KERNEL__ */
146#endif /* _NFNETLINK_H */ 148#endif /* _NFNETLINK_H */
diff --git a/net/core/netfilter.c b/net/core/netfilter.c
index 1ed4f3110421..3e38084ac2bd 100644
--- a/net/core/netfilter.c
+++ b/net/core/netfilter.c
@@ -221,7 +221,8 @@ static unsigned int nf_iterate(struct list_head *head,
221 verdict = elem->hook(hook, skb, indev, outdev, okfn); 221 verdict = elem->hook(hook, skb, indev, outdev, okfn);
222 if (verdict != NF_ACCEPT) { 222 if (verdict != NF_ACCEPT) {
223#ifdef CONFIG_NETFILTER_DEBUG 223#ifdef CONFIG_NETFILTER_DEBUG
224 if (unlikely(verdict > NF_MAX_VERDICT)) { 224 if (unlikely((verdict & NF_VERDICT_MASK)
225 > NF_MAX_VERDICT)) {
225 NFDEBUG("Evil return from %p(%u).\n", 226 NFDEBUG("Evil return from %p(%u).\n",
226 elem->hook, hook); 227 elem->hook, hook);
227 continue; 228 continue;
@@ -239,6 +240,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
239{ 240{
240 int ret; 241 int ret;
241 242
243 if (pf >= NPROTO)
244 return -EINVAL;
245
242 write_lock_bh(&queue_handler_lock); 246 write_lock_bh(&queue_handler_lock);
243 if (queue_handler[pf].outfn) 247 if (queue_handler[pf].outfn)
244 ret = -EBUSY; 248 ret = -EBUSY;
@@ -255,6 +259,9 @@ int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
255/* The caller must flush their queue before this */ 259/* The caller must flush their queue before this */
256int nf_unregister_queue_handler(int pf) 260int nf_unregister_queue_handler(int pf)
257{ 261{
262 if (pf >= NPROTO)
263 return -EINVAL;
264
258 write_lock_bh(&queue_handler_lock); 265 write_lock_bh(&queue_handler_lock);
259 queue_handler[pf].outfn = NULL; 266 queue_handler[pf].outfn = NULL;
260 queue_handler[pf].data = NULL; 267 queue_handler[pf].data = NULL;
@@ -286,6 +293,20 @@ int nf_unregister_queue_rerouter(int pf)
286 return 0; 293 return 0;
287} 294}
288 295
296void nf_unregister_queue_handlers(nf_queue_outfn_t outfn)
297{
298 int pf;
299
300 write_lock_bh(&queue_handler_lock);
301 for (pf = 0; pf < NPROTO; pf++) {
302 if (queue_handler[pf].outfn == outfn) {
303 queue_handler[pf].outfn = NULL;
304 queue_handler[pf].data = NULL;
305 }
306 }
307 write_unlock_bh(&queue_handler_lock);
308}
309
289/* 310/*
290 * Any packet that leaves via this function must come back 311 * Any packet that leaves via this function must come back
291 * through nf_reinject(). 312 * through nf_reinject().
@@ -295,7 +316,8 @@ static int nf_queue(struct sk_buff **skb,
295 int pf, unsigned int hook, 316 int pf, unsigned int hook,
296 struct net_device *indev, 317 struct net_device *indev,
297 struct net_device *outdev, 318 struct net_device *outdev,
298 int (*okfn)(struct sk_buff *)) 319 int (*okfn)(struct sk_buff *),
320 unsigned int queuenum)
299{ 321{
300 int status; 322 int status;
301 struct nf_info *info; 323 struct nf_info *info;
@@ -347,7 +369,8 @@ static int nf_queue(struct sk_buff **skb,
347 if (queue_rerouter[pf].save) 369 if (queue_rerouter[pf].save)
348 queue_rerouter[pf].save(*skb, info); 370 queue_rerouter[pf].save(*skb, info);
349 371
350 status = queue_handler[pf].outfn(*skb, info, queue_handler[pf].data); 372 status = queue_handler[pf].outfn(*skb, info, queuenum,
373 queue_handler[pf].data);
351 374
352 if (status >= 0 && queue_rerouter[pf].reroute) 375 if (status >= 0 && queue_rerouter[pf].reroute)
353 status = queue_rerouter[pf].reroute(skb, info); 376 status = queue_rerouter[pf].reroute(skb, info);
@@ -397,9 +420,10 @@ next_hook:
397 } else if (verdict == NF_DROP) { 420 } else if (verdict == NF_DROP) {
398 kfree_skb(*pskb); 421 kfree_skb(*pskb);
399 ret = -EPERM; 422 ret = -EPERM;
400 } else if (verdict == NF_QUEUE) { 423 } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) {
401 NFDEBUG("nf_hook: Verdict = QUEUE.\n"); 424 NFDEBUG("nf_hook: Verdict = QUEUE.\n");
402 if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn)) 425 if (!nf_queue(pskb, elem, pf, hook, indev, outdev, okfn,
426 verdict >> NF_VERDICT_BITS))
403 goto next_hook; 427 goto next_hook;
404 } 428 }
405unlock: 429unlock:
@@ -456,14 +480,15 @@ void nf_reinject(struct sk_buff *skb, struct nf_info *info,
456 info->okfn, INT_MIN); 480 info->okfn, INT_MIN);
457 } 481 }
458 482
459 switch (verdict) { 483 switch (verdict & NF_VERDICT_MASK) {
460 case NF_ACCEPT: 484 case NF_ACCEPT:
461 info->okfn(skb); 485 info->okfn(skb);
462 break; 486 break;
463 487
464 case NF_QUEUE: 488 case NF_QUEUE:
465 if (!nf_queue(&skb, elem, info->pf, info->hook, 489 if (!nf_queue(&skb, elem, info->pf, info->hook,
466 info->indev, info->outdev, info->okfn)) 490 info->indev, info->outdev, info->okfn,
491 verdict >> NF_VERDICT_BITS))
467 goto next_hook; 492 goto next_hook;
468 break; 493 break;
469 } 494 }
@@ -613,6 +638,7 @@ EXPORT_SYMBOL(nf_reinject);
613EXPORT_SYMBOL(nf_setsockopt); 638EXPORT_SYMBOL(nf_setsockopt);
614EXPORT_SYMBOL(nf_unregister_hook); 639EXPORT_SYMBOL(nf_unregister_hook);
615EXPORT_SYMBOL(nf_unregister_queue_handler); 640EXPORT_SYMBOL(nf_unregister_queue_handler);
641EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers);
616EXPORT_SYMBOL_GPL(nf_register_queue_rerouter); 642EXPORT_SYMBOL_GPL(nf_register_queue_rerouter);
617EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); 643EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter);
618EXPORT_SYMBOL(nf_unregister_sockopt); 644EXPORT_SYMBOL(nf_unregister_sockopt);
diff --git a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c
index 78892980f42c..cfc886f382ac 100644
--- a/net/ipv4/netfilter/ip_queue.c
+++ b/net/ipv4/netfilter/ip_queue.c
@@ -280,7 +280,8 @@ nlmsg_failure:
280} 280}
281 281
282static int 282static int
283ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) 283ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
284 unsigned int queuenum, void *data)
284{ 285{
285 int status = -EINVAL; 286 int status = -EINVAL;
286 struct sk_buff *nskb; 287 struct sk_buff *nskb;
diff --git a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c
index c45d8f8815de..5af4cee93d9b 100644
--- a/net/ipv6/netfilter/ip6_queue.c
+++ b/net/ipv6/netfilter/ip6_queue.c
@@ -278,7 +278,8 @@ nlmsg_failure:
278} 278}
279 279
280static int 280static int
281ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) 281ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info,
282 unsigned int queuenum, void *data)
282{ 283{
283 int status = -EINVAL; 284 int status = -EINVAL;
284 struct sk_buff *nskb; 285 struct sk_buff *nskb;
diff --git a/net/netfilter/nfnetlink.c b/net/netfilter/nfnetlink.c
index 6210ca42166c..30b25f47f7cc 100644
--- a/net/netfilter/nfnetlink.c
+++ b/net/netfilter/nfnetlink.c
@@ -44,7 +44,9 @@ MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_NETFILTER);
44static char __initdata nfversion[] = "0.30"; 44static char __initdata nfversion[] = "0.30";
45 45
46#if 0 46#if 0
47#define DEBUGP printk 47#define DEBUGP(format, args...) \
48 printk(KERN_DEBUG "%s(%d):%s(): " format, __FILE__, \
49 __LINE__, __FUNCTION__, ## args)
48#else 50#else
49#define DEBUGP(format, args...) 51#define DEBUGP(format, args...)
50#endif 52#endif
@@ -67,11 +69,11 @@ int nfnetlink_subsys_register(struct nfnetlink_subsystem *n)
67{ 69{
68 DEBUGP("registering subsystem ID %u\n", n->subsys_id); 70 DEBUGP("registering subsystem ID %u\n", n->subsys_id);
69 71
70 /* If the netlink socket wasn't created, then fail */
71 if (!nfnl)
72 return -1;
73
74 nfnl_lock(); 72 nfnl_lock();
73 if (subsys_table[n->subsys_id]) {
74 nfnl_unlock();
75 return -EBUSY;
76 }
75 subsys_table[n->subsys_id] = n; 77 subsys_table[n->subsys_id] = n;
76 nfnl_unlock(); 78 nfnl_unlock();
77 79
@@ -227,8 +229,18 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
227 229
228 type = nlh->nlmsg_type; 230 type = nlh->nlmsg_type;
229 ss = nfnetlink_get_subsys(type); 231 ss = nfnetlink_get_subsys(type);
230 if (!ss) 232 if (!ss) {
233#ifdef CONFIG_KMOD
234 /* don't call nfnl_shunlock, since it would reenter
235 * with further packet processing */
236 up(&nfnl_sem);
237 request_module("nfnetlink-subsys-%d", NFNL_SUBSYS_ID(type));
238 nfnl_shlock();
239 ss = nfnetlink_get_subsys(type);
240 if (!ss)
241#endif
231 goto err_inval; 242 goto err_inval;
243 }
232 244
233 nc = nfnetlink_find_client(type, ss); 245 nc = nfnetlink_find_client(type, ss);
234 if (!nc) { 246 if (!nc) {
@@ -252,12 +264,14 @@ static inline int nfnetlink_rcv_msg(struct sk_buff *skb,
252 if (err < 0) 264 if (err < 0)
253 goto err_inval; 265 goto err_inval;
254 266
267 DEBUGP("calling handler\n");
255 err = nc->call(nfnl, skb, nlh, cda, errp); 268 err = nc->call(nfnl, skb, nlh, cda, errp);
256 *errp = err; 269 *errp = err;
257 return err; 270 return err;
258 } 271 }
259 272
260err_inval: 273err_inval:
274 DEBUGP("returning -EINVAL\n");
261 *errp = -EINVAL; 275 *errp = -EINVAL;
262 return -1; 276 return -1;
263} 277}
@@ -311,6 +325,8 @@ static void nfnetlink_rcv(struct sock *sk, int len)
311 kfree_skb(skb); 325 kfree_skb(skb);
312 } 326 }
313 327
328 /* don't call nfnl_shunlock, since it would reenter
329 * with further packet processing */
314 up(&nfnl_sem); 330 up(&nfnl_sem);
315 } while(nfnl && nfnl->sk_receive_queue.qlen); 331 } while(nfnl && nfnl->sk_receive_queue.qlen);
316} 332}