diff options
author | Harald Welte <laforge@netfilter.org> | 2005-08-09 22:43:44 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2005-08-29 18:36:49 -0400 |
commit | 0ab43f84995f2c2fcc5cc58a9accaa1095e1317f (patch) | |
tree | f58711648f91bbd880fcada7718a2462f0249a78 | |
parent | 2cc7d5730957c4a3f3659d17d2ba5e06d5581c1f (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.h | 14 | ||||
-rw-r--r-- | include/linux/netfilter/nfnetlink.h | 20 | ||||
-rw-r--r-- | net/core/netfilter.c | 40 | ||||
-rw-r--r-- | net/ipv4/netfilter/ip_queue.c | 3 | ||||
-rw-r--r-- | net/ipv6/netfilter/ip6_queue.c | 3 | ||||
-rw-r--r-- | net/netfilter/nfnetlink.c | 28 |
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 */ |
181 | typedef int (*nf_queue_outfn_t)(struct sk_buff *skb, | 191 | typedef 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); | ||
183 | extern int nf_register_queue_handler(int pf, | 194 | extern int nf_register_queue_handler(int pf, |
184 | nf_queue_outfn_t outfn, void *data); | 195 | nf_queue_outfn_t outfn, void *data); |
185 | extern int nf_unregister_queue_handler(int pf); | 196 | extern int nf_unregister_queue_handler(int pf); |
197 | extern void nf_unregister_queue_handlers(nf_queue_outfn_t outfn); | ||
186 | extern void nf_reinject(struct sk_buff *skb, | 198 | extern 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 | ||
72 | enum 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); |
143 | extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); | 142 | extern 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 */ |
256 | int nf_unregister_queue_handler(int pf) | 260 | int 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 | ||
296 | void 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 | } |
405 | unlock: | 429 | unlock: |
@@ -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); | |||
613 | EXPORT_SYMBOL(nf_setsockopt); | 638 | EXPORT_SYMBOL(nf_setsockopt); |
614 | EXPORT_SYMBOL(nf_unregister_hook); | 639 | EXPORT_SYMBOL(nf_unregister_hook); |
615 | EXPORT_SYMBOL(nf_unregister_queue_handler); | 640 | EXPORT_SYMBOL(nf_unregister_queue_handler); |
641 | EXPORT_SYMBOL_GPL(nf_unregister_queue_handlers); | ||
616 | EXPORT_SYMBOL_GPL(nf_register_queue_rerouter); | 642 | EXPORT_SYMBOL_GPL(nf_register_queue_rerouter); |
617 | EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); | 643 | EXPORT_SYMBOL_GPL(nf_unregister_queue_rerouter); |
618 | EXPORT_SYMBOL(nf_unregister_sockopt); | 644 | EXPORT_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 | ||
282 | static int | 282 | static int |
283 | ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) | 283 | ipq_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 | ||
280 | static int | 280 | static int |
281 | ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) | 281 | ipq_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); | |||
44 | static char __initdata nfversion[] = "0.30"; | 44 | static 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 | ||
260 | err_inval: | 273 | err_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 | } |