Main Page | Class List | File List | Class Members | File Members

netfilter.c

Go to the documentation of this file.
00001 /* netfilter.c: look after the filters for various protocols. 00002 * Heavily influenced by the old firewall.c by David Bonn and Alan Cox. 00003 * 00004 * Thanks to Rob `CmdrTaco' Malda for not influencing this code in any 00005 * way. 00006 * 00007 * Rusty Russell (C)2000 -- This code is GPL. 00008 * 00009 * February 2000: Modified by James Morris to have 1 queue per protocol. 00010 * 15-Mar-2000: Added NF_REPEAT --RR. 00011 */ 00012 #include <linux/config.h> 00013 #include <linux/netfilter.h> 00014 #include <net/protocol.h> 00015 #include <linux/init.h> 00016 #include <linux/skbuff.h> 00017 #include <linux/wait.h> 00018 #include <linux/module.h> 00019 #include <linux/interrupt.h> 00020 #include <linux/if.h> 00021 #include <linux/netdevice.h> 00022 #include <linux/brlock.h> 00023 #include <linux/inetdevice.h> 00024 #include <net/sock.h> 00025 #include <net/route.h> 00026 #include <linux/ip.h> 00027 00028 #define __KERNEL_SYSCALLS__ 00029 #include <linux/unistd.h> 00030 00031 /* In this code, we can be waiting indefinitely for userspace to 00032 * service a packet if a hook returns NF_QUEUE. We could keep a count 00033 * of skbuffs queued for userspace, and not deregister a hook unless 00034 * this is zero, but that sucks. Now, we simply check when the 00035 * packets come back: if the hook is gone, the packet is discarded. */ 00036 #ifdef CONFIG_NETFILTER_DEBUG 00037 #define NFDEBUG(format, args...) printk(format , ## args) 00038 #else 00039 #define NFDEBUG(format, args...) 00040 #endif 00041 00042 /* Sockopts only registered and called from user context, so 00043 BR_NETPROTO_LOCK would be overkill. Also, [gs]etsockopt calls may 00044 sleep. */ 00045 static DECLARE_MUTEX(nf_sockopt_mutex); 00046 00047 struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; 00048 static LIST_HEAD(nf_sockopts); 00049 00050 /* 00051 * A queue handler may be registered for each protocol. Each is protected by 00052 * long term mutex. The handler must provide an an outfn() to accept packets 00053 * for queueing and must reinject all packets it receives, no matter what. 00054 */ 00055 static struct nf_queue_handler_t { 00056 nf_queue_outfn_t outfn; 00057 void *data; 00058 } queue_handler[NPROTO]; 00059 00060 int nf_register_hook(struct nf_hook_ops *reg) 00061 { 00062 struct list_head *i; 00063 00064 br_write_lock_bh(BR_NETPROTO_LOCK); 00065 for (i = nf_hooks[reg->pf][reg->hooknum].next; 00066 i != &nf_hooks[reg->pf][reg->hooknum]; 00067 i = i->next) { 00068 if (reg->priority < ((struct nf_hook_ops *)i)->priority) 00069 break; 00070 } 00071 list_add(&reg->list, i->prev); 00072 br_write_unlock_bh(BR_NETPROTO_LOCK); 00073 return 0; 00074 } 00075 00076 void nf_unregister_hook(struct nf_hook_ops *reg) 00077 { 00078 br_write_lock_bh(BR_NETPROTO_LOCK); 00079 list_del(&reg->list); 00080 br_write_unlock_bh(BR_NETPROTO_LOCK); 00081 } 00082 00083 /* Do exclusive ranges overlap? */ 00084 static inline int overlap(int min1, int max1, int min2, int max2) 00085 { 00086 return max1 > min2 && min1 < max2; 00087 } 00088 00089 /* Functions to register sockopt ranges (exclusive). */ 00090 int nf_register_sockopt(struct nf_sockopt_ops *reg) 00091 { 00092 struct list_head *i; 00093 int ret = 0; 00094 00095 if (down_interruptible(&nf_sockopt_mutex) != 0) 00096 return -EINTR; 00097 00098 for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) { 00099 struct nf_sockopt_ops *ops = (struct nf_sockopt_ops *)i; 00100 if (ops->pf == reg->pf 00101 && (overlap(ops->set_optmin, ops->set_optmax, 00102 reg->set_optmin, reg->set_optmax) 00103 || overlap(ops->get_optmin, ops->get_optmax, 00104 reg->get_optmin, reg->get_optmax))) { 00105 NFDEBUG("nf_sock overlap: %u-%u/%u-%u v %u-%u/%u-%u\n", 00106 ops->set_optmin, ops->set_optmax, 00107 ops->get_optmin, ops->get_optmax, 00108 reg->set_optmin, reg->set_optmax, 00109 reg->get_optmin, reg->get_optmax); 00110 ret = -EBUSY; 00111 goto out; 00112 } 00113 } 00114 00115 list_add(&reg->list, &nf_sockopts); 00116 out: 00117 up(&nf_sockopt_mutex); 00118 return ret; 00119 } 00120 00121 void nf_unregister_sockopt(struct nf_sockopt_ops *reg) 00122 { 00123 /* No point being interruptible: we're probably in cleanup_module() */ 00124 restart: 00125 down(&nf_sockopt_mutex); 00126 if (reg->use != 0) { 00127 /* To be woken by nf_sockopt call... */ 00128 /* FIXME: Stuart Young's name appears gratuitously. */ 00129 set_current_state(TASK_UNINTERRUPTIBLE); 00130 reg->cleanup_task = current; 00131 up(&nf_sockopt_mutex); 00132 schedule(); 00133 goto restart; 00134 } 00135 list_del(&reg->list); 00136 up(&nf_sockopt_mutex); 00137 } 00138 00139 #ifdef CONFIG_NETFILTER_DEBUG 00140 #include <net/ip.h> 00141 #include <net/route.h> 00142 #include <net/tcp.h> 00143 #include <linux/netfilter_ipv4.h> 00144 00145 static void debug_print_hooks_ip(unsigned int nf_debug) 00146 { 00147 if (nf_debug & (1 << NF_IP_PRE_ROUTING)) { 00148 printk("PRE_ROUTING "); 00149 nf_debug ^= (1 << NF_IP_PRE_ROUTING); 00150 } 00151 if (nf_debug & (1 << NF_IP_LOCAL_IN)) { 00152 printk("LOCAL_IN "); 00153 nf_debug ^= (1 << NF_IP_LOCAL_IN); 00154 } 00155 if (nf_debug & (1 << NF_IP_FORWARD)) { 00156 printk("FORWARD "); 00157 nf_debug ^= (1 << NF_IP_FORWARD); 00158 } 00159 if (nf_debug & (1 << NF_IP_LOCAL_OUT)) { 00160 printk("LOCAL_OUT "); 00161 nf_debug ^= (1 << NF_IP_LOCAL_OUT); 00162 } 00163 if (nf_debug & (1 << NF_IP_POST_ROUTING)) { 00164 printk("POST_ROUTING "); 00165 nf_debug ^= (1 << NF_IP_POST_ROUTING); 00166 } 00167 if (nf_debug) 00168 printk("Crap bits: 0x%04X", nf_debug); 00169 printk("\n"); 00170 } 00171 00172 void nf_dump_skb(int pf, struct sk_buff *skb) 00173 { 00174 printk("skb: pf=%i %s dev=%s len=%u\n", 00175 pf, 00176 skb->sk ? "(owned)" : "(unowned)", 00177 skb->dev ? skb->dev->name : "(no dev)", 00178 skb->len); 00179 switch (pf) { 00180 case PF_INET: { 00181 const struct iphdr *ip = skb->nh.iph; 00182 __u32 *opt = (__u32 *) (ip + 1); 00183 int opti; 00184 __u16 src_port = 0, dst_port = 0; 00185 00186 if (ip->protocol == IPPROTO_TCP 00187 || ip->protocol == IPPROTO_UDP) { 00188 struct tcphdr *tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl); 00189 src_port = ntohs(tcp->source); 00190 dst_port = ntohs(tcp->dest); 00191 } 00192 00193 printk("PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu" 00194 " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu", 00195 ip->protocol, NIPQUAD(ip->saddr), 00196 src_port, NIPQUAD(ip->daddr), 00197 dst_port, 00198 ntohs(ip->tot_len), ip->tos, ntohs(ip->id), 00199 ntohs(ip->frag_off), ip->ttl); 00200 00201 for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++) 00202 printk(" O=0x%8.8X", *opt++); 00203 printk("\n"); 00204 } 00205 } 00206 } 00207 00208 void nf_debug_ip_local_deliver(struct sk_buff *skb) 00209 { 00210 /* If it's a loopback packet, it must have come through 00211 * NF_IP_LOCAL_OUT, NF_IP_RAW_INPUT, NF_IP_PRE_ROUTING and 00212 * NF_IP_LOCAL_IN. Otherwise, must have gone through 00213 * NF_IP_RAW_INPUT and NF_IP_PRE_ROUTING. */ 00214 if (!skb->dev) { 00215 printk("ip_local_deliver: skb->dev is NULL.\n"); 00216 } 00217 else if (strcmp(skb->dev->name, "lo") == 0) { 00218 if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) 00219 | (1 << NF_IP_POST_ROUTING) 00220 | (1 << NF_IP_PRE_ROUTING) 00221 | (1 << NF_IP_LOCAL_IN))) { 00222 printk("ip_local_deliver: bad loopback skb: "); 00223 debug_print_hooks_ip(skb->nf_debug); 00224 nf_dump_skb(PF_INET, skb); 00225 } 00226 } 00227 else { 00228 if (skb->nf_debug != ((1<<NF_IP_PRE_ROUTING) 00229 | (1<<NF_IP_LOCAL_IN))) { 00230 printk("ip_local_deliver: bad non-lo skb: "); 00231 debug_print_hooks_ip(skb->nf_debug); 00232 nf_dump_skb(PF_INET, skb); 00233 } 00234 } 00235 } 00236 00237 void nf_debug_ip_loopback_xmit(struct sk_buff *newskb) 00238 { 00239 if (newskb->nf_debug != ((1 << NF_IP_LOCAL_OUT) 00240 | (1 << NF_IP_POST_ROUTING))) { 00241 printk("ip_dev_loopback_xmit: bad owned skb = %p: ", 00242 newskb); 00243 debug_print_hooks_ip(newskb->nf_debug); 00244 nf_dump_skb(PF_INET, newskb); 00245 } 00246 /* Clear to avoid confusing input check */ 00247 newskb->nf_debug = 0; 00248 } 00249 00250 void nf_debug_ip_finish_output2(struct sk_buff *skb) 00251 { 00252 /* If it's owned, it must have gone through the 00253 * NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING. 00254 * Otherwise, must have gone through 00255 * NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING. 00256 */ 00257 if (skb->sk) { 00258 if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) 00259 | (1 << NF_IP_POST_ROUTING))) { 00260 printk("ip_finish_output: bad owned skb = %p: ", skb); 00261 debug_print_hooks_ip(skb->nf_debug); 00262 nf_dump_skb(PF_INET, skb); 00263 } 00264 } else { 00265 if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING) 00266 | (1 << NF_IP_FORWARD) 00267 | (1 << NF_IP_POST_ROUTING))) { 00268 /* Fragments, entunnelled packets, TCP RSTs 00269 generated by ipt_REJECT will have no 00270 owners, but still may be local */ 00271 if (skb->nf_debug != ((1 << NF_IP_LOCAL_OUT) 00272 | (1 << NF_IP_POST_ROUTING))){ 00273 printk("ip_finish_output:" 00274 " bad unowned skb = %p: ",skb); 00275 debug_print_hooks_ip(skb->nf_debug); 00276 nf_dump_skb(PF_INET, skb); 00277 } 00278 } 00279 } 00280 } 00281 #endif /*CONFIG_NETFILTER_DEBUG*/ 00282 00283 /* Call get/setsockopt() */ 00284 static int nf_sockopt(struct sock *sk, int pf, int val, 00285 char *opt, int *len, int get) 00286 { 00287 struct list_head *i; 00288 struct nf_sockopt_ops *ops; 00289 int ret; 00290 00291 if (down_interruptible(&nf_sockopt_mutex) != 0) 00292 return -EINTR; 00293 00294 for (i = nf_sockopts.next; i != &nf_sockopts; i = i->next) { 00295 ops = (struct nf_sockopt_ops *)i; 00296 if (ops->pf == pf) { 00297 if (get) { 00298 if (val >= ops->get_optmin 00299 && val < ops->get_optmax) { 00300 ops->use++; 00301 up(&nf_sockopt_mutex); 00302 ret = ops->get(sk, val, opt, len); 00303 goto out; 00304 } 00305 } else { 00306 if (val >= ops->set_optmin 00307 && val < ops->set_optmax) { 00308 ops->use++; 00309 up(&nf_sockopt_mutex); 00310 ret = ops->set(sk, val, opt, *len); 00311 goto out; 00312 } 00313 } 00314 } 00315 } 00316 up(&nf_sockopt_mutex); 00317 return -ENOPROTOOPT; 00318 00319 out: 00320 down(&nf_sockopt_mutex); 00321 ops->use--; 00322 if (ops->cleanup_task) 00323 wake_up_process(ops->cleanup_task); 00324 up(&nf_sockopt_mutex); 00325 return ret; 00326 } 00327 00328 int nf_setsockopt(struct sock *sk, int pf, int val, char *opt, 00329 int len) 00330 { 00331 return nf_sockopt(sk, pf, val, opt, &len, 0); 00332 } 00333 00334 int nf_getsockopt(struct sock *sk, int pf, int val, char *opt, int *len) 00335 { 00336 return nf_sockopt(sk, pf, val, opt, len, 1); 00337 } 00338 00339 static unsigned int nf_iterate(struct list_head *head, 00340 struct sk_buff **skb, 00341 int hook, 00342 const struct net_device *indev, 00343 const struct net_device *outdev, 00344 struct list_head **i, 00345 int (*okfn)(struct sk_buff *)) 00346 { 00347 for (*i = (*i)->next; *i != head; *i = (*i)->next) { 00348 struct nf_hook_ops *elem = (struct nf_hook_ops *)*i; 00349 switch (elem->hook(hook, skb, indev, outdev, okfn)) { 00350 case NF_QUEUE: 00351 return NF_QUEUE; 00352 00353 case NF_STOLEN: 00354 return NF_STOLEN; 00355 00356 case NF_DROP: 00357 return NF_DROP; 00358 00359 case NF_REPEAT: 00360 *i = (*i)->prev; 00361 break; 00362 00363 #ifdef CONFIG_NETFILTER_DEBUG 00364 case NF_ACCEPT: 00365 break; 00366 00367 default: 00368 NFDEBUG("Evil return from %p(%u).\n", 00369 elem->hook, hook); 00370 #endif 00371 } 00372 } 00373 return NF_ACCEPT; 00374 } 00375 00376 int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data) 00377 { 00378 int ret; 00379 00380 br_write_lock_bh(BR_NETPROTO_LOCK); 00381 if (queue_handler[pf].outfn) 00382 ret = -EBUSY; 00383 else { 00384 queue_handler[pf].outfn = outfn; 00385 queue_handler[pf].data = data; 00386 ret = 0; 00387 } 00388 br_write_unlock_bh(BR_NETPROTO_LOCK); 00389 00390 return ret; 00391 } 00392 00393 /* The caller must flush their queue before this */ 00394 int nf_unregister_queue_handler(int pf) 00395 { 00396 br_write_lock_bh(BR_NETPROTO_LOCK); 00397 queue_handler[pf].outfn = NULL; 00398 queue_handler[pf].data = NULL; 00399 br_write_unlock_bh(BR_NETPROTO_LOCK); 00400 return 0; 00401 } 00402 00403 /* 00404 * Any packet that leaves via this function must come back 00405 * through nf_reinject(). 00406 */ 00407 static void nf_queue(struct sk_buff *skb, 00408 struct list_head *elem, 00409 int pf, unsigned int hook, 00410 struct net_device *indev, 00411 struct net_device *outdev, 00412 int (*okfn)(struct sk_buff *)) 00413 { 00414 int status; 00415 struct nf_info *info; 00416 00417 if (!queue_handler[pf].outfn) { 00418 kfree_skb(skb); 00419 return; 00420 } 00421 00422 info = kmalloc(sizeof(*info), GFP_ATOMIC); 00423 if (!info) { 00424 if (net_ratelimit()) 00425 printk(KERN_ERR "OOM queueing packet %p\n", 00426 skb); 00427 kfree_skb(skb); 00428 return; 00429 } 00430 00431 *info = (struct nf_info) { 00432 (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn }; 00433 00434 /* Bump dev refs so they don't vanish while packet is out */ 00435 if (indev) dev_hold(indev); 00436 if (outdev) dev_hold(outdev); 00437 00438 status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data); 00439 if (status < 0) { 00440 /* James M doesn't say fuck enough. */ 00441 if (indev) dev_put(indev); 00442 if (outdev) dev_put(outdev); 00443 kfree(info); 00444 kfree_skb(skb); 00445 return; 00446 } 00447 } 00448 00449 int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, 00450 struct net_device *indev, 00451 struct net_device *outdev, 00452 int (*okfn)(struct sk_buff *)) 00453 { 00454 struct list_head *elem; 00455 unsigned int verdict; 00456 int ret = 0; 00457 00458 /* This stopgap cannot be removed until all the hooks are audited. */ 00459 if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) { 00460 kfree_skb(skb); 00461 return -ENOMEM; 00462 } 00463 if (skb->ip_summed == CHECKSUM_HW) { 00464 if (outdev == NULL) { 00465 skb->ip_summed = CHECKSUM_NONE; 00466 } else { 00467 skb_checksum_help(skb); 00468 } 00469 } 00470 00471 /* We may already have this, but read-locks nest anyway */ 00472 br_read_lock_bh(BR_NETPROTO_LOCK); 00473 00474 #ifdef CONFIG_NETFILTER_DEBUG 00475 if (skb->nf_debug & (1 << hook)) { 00476 printk("nf_hook: hook %i already set.\n", hook); 00477 nf_dump_skb(pf, skb); 00478 } 00479 skb->nf_debug |= (1 << hook); 00480 #endif 00481 00482 elem = &nf_hooks[pf][hook]; 00483 verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev, 00484 outdev, &elem, okfn); 00485 if (verdict == NF_QUEUE) { 00486 NFDEBUG("nf_hook: Verdict = QUEUE.\n"); 00487 nf_queue(skb, elem, pf, hook, indev, outdev, okfn); 00488 } 00489 00490 switch (verdict) { 00491 case NF_ACCEPT: 00492 ret = okfn(skb); 00493 break; 00494 00495 case NF_DROP: 00496 kfree_skb(skb); 00497 ret = -EPERM; 00498 break; 00499 } 00500 00501 br_read_unlock_bh(BR_NETPROTO_LOCK); 00502 return ret; 00503 } 00504 00505 void nf_reinject(struct sk_buff *skb, struct nf_info *info, 00506 unsigned int verdict) 00507 { 00508 struct list_head *elem = &info->elem->list; 00509 struct list_head *i; 00510 00511 /* We don't have BR_NETPROTO_LOCK here */ 00512 br_read_lock_bh(BR_NETPROTO_LOCK); 00513 for (i = nf_hooks[info->pf][info->hook].next; i != elem; i = i->next) { 00514 if (i == &nf_hooks[info->pf][info->hook]) { 00515 /* The module which sent it to userspace is gone. */ 00516 NFDEBUG("%s: module disappeared, dropping packet.\n", 00517 __FUNCTION__); 00518 verdict = NF_DROP; 00519 break; 00520 } 00521 } 00522 00523 /* Continue traversal iff userspace said ok... */ 00524 if (verdict == NF_REPEAT) { 00525 elem = elem->prev; 00526 verdict = NF_ACCEPT; 00527 } 00528 00529 if (verdict == NF_ACCEPT) { 00530 verdict = nf_iterate(&nf_hooks[info->pf][info->hook], 00531 &skb, info->hook, 00532 info->indev, info->outdev, &elem, 00533 info->okfn); 00534 } 00535 00536 switch (verdict) { 00537 case NF_ACCEPT: 00538 info->okfn(skb); 00539 break; 00540 00541 case NF_QUEUE: 00542 nf_queue(skb, elem, info->pf, info->hook, 00543 info->indev, info->outdev, info->okfn); 00544 break; 00545 00546 case NF_DROP: 00547 kfree_skb(skb); 00548 break; 00549 } 00550 br_read_unlock_bh(BR_NETPROTO_LOCK); 00551 00552 /* Release those devices we held, or Alexey will kill me. */ 00553 if (info->indev) dev_put(info->indev); 00554 if (info->outdev) dev_put(info->outdev); 00555 00556 kfree(info); 00557 return; 00558 } 00559 00560 #ifdef CONFIG_INET 00561 /* route_me_harder function, used by iptable_nat, iptable_mangle + ip_queue */ 00562 int ip_route_me_harder(struct sk_buff **pskb) 00563 { 00564 struct iphdr *iph = (*pskb)->nh.iph; 00565 struct rtable *rt; 00566 struct rt_key key = {}; 00567 struct dst_entry *odst; 00568 unsigned int hh_len; 00569 00570 /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause 00571 * packets with foreign saddr to be appear on the NF_IP_LOCAL_OUT hook. 00572 */ 00573 if (inet_addr_type(iph->saddr) == RTN_LOCAL) { 00574 key.dst = iph->daddr; 00575 key.src = iph->saddr; 00576 key.oif = (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0; 00577 key.tos = RT_TOS(iph->tos); 00578 #ifdef CONFIG_IP_ROUTE_FWMARK 00579 key.fwmark = (*pskb)->nfmark; 00580 #endif 00581 if (ip_route_output_key(&rt, &key) != 0) 00582 return -1; 00583 00584 /* Drop old route. */ 00585 dst_release((*pskb)->dst); 00586 (*pskb)->dst = &rt->u.dst; 00587 } else { 00588 /* non-local src, find valid iif to satisfy 00589 * rp-filter when calling ip_route_input. */ 00590 key.dst = iph->saddr; 00591 if (ip_route_output_key(&rt, &key) != 0) 00592 return -1; 00593 00594 odst = (*pskb)->dst; 00595 if (ip_route_input(*pskb, iph->daddr, iph->saddr, 00596 RT_TOS(iph->tos), rt->u.dst.dev) != 0) { 00597 dst_release(&rt->u.dst); 00598 return -1; 00599 } 00600 dst_release(&rt->u.dst); 00601 dst_release(odst); 00602 } 00603 00604 if ((*pskb)->dst->error) 00605 return -1; 00606 00607 /* Change in oif may mean change in hh_len. */ 00608 hh_len = (*pskb)->dst->dev->hard_header_len; 00609 if (skb_headroom(*pskb) < hh_len) { 00610 struct sk_buff *nskb; 00611 00612 nskb = skb_realloc_headroom(*pskb, hh_len); 00613 if (!nskb) 00614 return -1; 00615 if ((*pskb)->sk) 00616 skb_set_owner_w(nskb, (*pskb)->sk); 00617 kfree_skb(*pskb); 00618 *pskb = nskb; 00619 } 00620 00621 return 0; 00622 } 00623 #endif /*CONFIG_INET*/ 00624 00625 /* This does not belong here, but ipt_REJECT needs it if connection 00626 tracking in use: without this, connection may not be in hash table, 00627 and hence manufactured ICMP or RST packets will not be associated 00628 with it. */ 00629 void (*ip_ct_attach)(struct sk_buff *, struct nf_ct_info *); 00630 00631 void __init netfilter_init(void) 00632 { 00633 int i, h; 00634 00635 for (i = 0; i < NPROTO; i++) { 00636 for (h = 0; h < NF_MAX_HOOKS; h++) 00637 INIT_LIST_HEAD(&nf_hooks[i][h]); 00638 } 00639 }

Generated on Wed Dec 1 21:25:32 2004 for Linux 2.4.23 Networking by doxygen 1.3.8