2 * Packet matching code.
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
14 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
15 * - new extension header parser code
17 #include <linux/config.h>
18 #include <linux/skbuff.h>
19 #include <linux/kmod.h>
20 #include <linux/vmalloc.h>
21 #include <linux/netdevice.h>
22 #include <linux/module.h>
23 #include <linux/tcp.h>
24 #include <linux/udp.h>
25 #include <linux/icmpv6.h>
28 #include <asm/uaccess.h>
29 #include <asm/semaphore.h>
30 #include <linux/proc_fs.h>
32 #include <linux/netfilter_ipv6/ip6_tables.h>
34 MODULE_LICENSE("GPL");
35 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
36 MODULE_DESCRIPTION("IPv6 packet filter");
38 #define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
39 #define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
41 /*#define DEBUG_IP_FIREWALL*/
42 /*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
43 /*#define DEBUG_IP_FIREWALL_USER*/
45 #ifdef DEBUG_IP_FIREWALL
46 #define dprintf(format, args...) printk(format , ## args)
48 #define dprintf(format, args...)
51 #ifdef DEBUG_IP_FIREWALL_USER
52 #define duprintf(format, args...) printk(format , ## args)
54 #define duprintf(format, args...)
57 #ifdef CONFIG_NETFILTER_DEBUG
58 #define IP_NF_ASSERT(x) \
61 printk("IP_NF_ASSERT: %s:%s:%u\n", \
62 __FUNCTION__, __FILE__, __LINE__); \
65 #define IP_NF_ASSERT(x)
67 #define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
69 /* Mutex protects lists (only traversed in user context). */
70 static DECLARE_MUTEX(ip6t_mutex);
73 #define ASSERT_READ_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
74 #define ASSERT_WRITE_LOCK(x) IP_NF_ASSERT(down_trylock(&ip6t_mutex) != 0)
75 #include <linux/netfilter_ipv4/lockhelp.h>
76 #include <linux/netfilter_ipv4/listhelp.h>
79 /* All the better to debug you with... */
84 /* Locking is simple: we assume at worst case there will be one packet
85 in user context and one from bottom halves (or soft irq if Alexey's
86 softnet patch was applied).
88 We keep a set of rules for each CPU, so we can avoid write-locking
89 them; doing a readlock_bh() stops packets coming through if we're
92 To be cache friendly on SMP, we arrange them like so:
94 ... cache-align padding ...
97 Hence the start of any table is given by get_table() below. */
99 /* The table itself */
100 struct ip6t_table_info
104 /* Number of entries: FIXME. --RR */
106 /* Initial number of entries. Needed for module usage count */
107 unsigned int initial_entries;
109 /* Entry points and underflows */
110 unsigned int hook_entry[NF_IP6_NUMHOOKS];
111 unsigned int underflow[NF_IP6_NUMHOOKS];
113 /* ip6t_entry tables: one per CPU */
114 char entries[0] ____cacheline_aligned;
117 static LIST_HEAD(ip6t_target);
118 static LIST_HEAD(ip6t_match);
119 static LIST_HEAD(ip6t_tables);
120 #define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
123 #define TABLE_OFFSET(t,p) (SMP_ALIGN((t)->size)*(p))
125 #define TABLE_OFFSET(t,p) 0
129 #define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
130 #define down_interruptible(x) ({ int __r; printk("DOWNi:%u:" #x "\n", __LINE__); __r = down_interruptible(x); if (__r != 0) printk("ABORT-DOWNi:%u\n", __LINE__); __r; })
131 #define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
134 static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
135 struct in6_addr addr2)
138 for( i = 0; i < 16; i++){
139 if((addr1.s6_addr[i] & mask.s6_addr[i]) !=
140 (addr2.s6_addr[i] & mask.s6_addr[i]))
146 /* Check for an extension */
148 ip6t_ext_hdr(u8 nexthdr)
150 return ( (nexthdr == IPPROTO_HOPOPTS) ||
151 (nexthdr == IPPROTO_ROUTING) ||
152 (nexthdr == IPPROTO_FRAGMENT) ||
153 (nexthdr == IPPROTO_ESP) ||
154 (nexthdr == IPPROTO_AH) ||
155 (nexthdr == IPPROTO_NONE) ||
156 (nexthdr == IPPROTO_DSTOPTS) );
159 /* Returns whether matches rule or not. */
161 ip6_packet_match(const struct sk_buff *skb,
162 const struct ipv6hdr *ipv6,
165 const struct ip6t_ip6 *ip6info,
171 #define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
173 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
175 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
177 dprintf("Source or dest mismatch.\n");
179 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
180 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
181 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
182 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
183 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
184 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
188 /* Look for ifname matches; this should unroll nicely. */
189 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
190 ret |= (((const unsigned long *)indev)[i]
191 ^ ((const unsigned long *)ip6info->iniface)[i])
192 & ((const unsigned long *)ip6info->iniface_mask)[i];
195 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
196 dprintf("VIA in mismatch (%s vs %s).%s\n",
197 indev, ip6info->iniface,
198 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
202 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
203 ret |= (((const unsigned long *)outdev)[i]
204 ^ ((const unsigned long *)ip6info->outiface)[i])
205 & ((const unsigned long *)ip6info->outiface_mask)[i];
208 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
209 dprintf("VIA out mismatch (%s vs %s).%s\n",
210 outdev, ip6info->outiface,
211 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
215 /* ... might want to do something with class and flowlabel here ... */
217 /* look for the desired protocol header */
218 if((ip6info->flags & IP6T_F_PROTO)) {
219 u_int8_t currenthdr = ipv6->nexthdr;
220 struct ipv6_opt_hdr *hdrptr;
221 u_int16_t ptr; /* Header offset in skb */
222 u_int16_t hdrlen; /* Header */
226 while (ip6t_ext_hdr(currenthdr)) {
227 /* Is there enough space for the next ext header? */
228 if (skb->len - ptr < IPV6_OPTHDR_LEN)
231 /* NONE or ESP: there isn't protocol part */
232 /* If we want to count these packets in '-p all',
233 * we will change the return 0 to 1*/
234 if ((currenthdr == IPPROTO_NONE) ||
235 (currenthdr == IPPROTO_ESP))
238 hdrptr = (struct ipv6_opt_hdr *)(skb->data + ptr);
240 /* Size calculation */
241 if (currenthdr == IPPROTO_FRAGMENT) {
243 } else if (currenthdr == IPPROTO_AH)
244 hdrlen = (hdrptr->hdrlen+2)<<2;
246 hdrlen = ipv6_optlen(hdrptr);
248 currenthdr = hdrptr->nexthdr;
250 /* ptr is too large */
251 if ( ptr > skb->len )
255 /* currenthdr contains the protocol header */
257 dprintf("Packet protocol %hi ?= %s%hi.\n",
259 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
262 if (ip6info->proto == currenthdr) {
263 if(ip6info->invflags & IP6T_INV_PROTO) {
269 /* We need match for the '-p all', too! */
270 if ((ip6info->proto != 0) &&
271 !(ip6info->invflags & IP6T_INV_PROTO))
277 /* should be ip6 safe */
279 ip6_checkentry(const struct ip6t_ip6 *ipv6)
281 if (ipv6->flags & ~IP6T_F_MASK) {
282 duprintf("Unknown flag bits set: %08X\n",
283 ipv6->flags & ~IP6T_F_MASK);
286 if (ipv6->invflags & ~IP6T_INV_MASK) {
287 duprintf("Unknown invflag bits set: %08X\n",
288 ipv6->invflags & ~IP6T_INV_MASK);
295 ip6t_error(struct sk_buff **pskb,
296 unsigned int hooknum,
297 const struct net_device *in,
298 const struct net_device *out,
299 const void *targinfo,
303 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
309 int do_match(struct ip6t_entry_match *m,
310 const struct sk_buff *skb,
311 const struct net_device *in,
312 const struct net_device *out,
318 /* Stop iteration if it doesn't match */
319 if (!m->u.kernel.match->match(skb, in, out, m->data,
320 offset, hdr, datalen, hotdrop))
326 static inline struct ip6t_entry *
327 get_entry(void *base, unsigned int offset)
329 return (struct ip6t_entry *)(base + offset);
332 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
334 ip6t_do_table(struct sk_buff **pskb,
336 const struct net_device *in,
337 const struct net_device *out,
338 struct ip6t_table *table,
341 static const char nulldevname[IFNAMSIZ];
342 u_int16_t offset = 0;
343 struct ipv6hdr *ipv6;
347 /* Initializing verdict to NF_DROP keeps gcc happy. */
348 unsigned int verdict = NF_DROP;
349 const char *indev, *outdev;
351 struct ip6t_entry *e, *back;
353 /* FIXME: Push down to extensions --RR */
354 if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
358 ipv6 = (*pskb)->nh.ipv6h;
359 protohdr = (u_int32_t *)((char *)ipv6 + IPV6_HDR_LEN);
360 datalen = (*pskb)->len - IPV6_HDR_LEN;
361 indev = in ? in->name : nulldevname;
362 outdev = out ? out->name : nulldevname;
364 /* We handle fragments by dealing with the first fragment as
365 * if it was a normal packet. All other fragments are treated
366 * normally, except that they will NEVER match rules that ask
367 * things we don't know, ie. tcp syn flag or ports). If the
368 * rule is also a fragment-specific rule, non-fragments won't
371 read_lock_bh(&table->lock);
372 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
373 table_base = (void *)table->private->entries
374 + TABLE_OFFSET(table->private, smp_processor_id());
375 e = get_entry(table_base, table->private->hook_entry[hook]);
377 #ifdef CONFIG_NETFILTER_DEBUG
378 /* Check noone else using our table */
379 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
380 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
381 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
384 &((struct ip6t_entry *)table_base)->comefrom,
385 ((struct ip6t_entry *)table_base)->comefrom);
387 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
390 /* For return from builtin chain */
391 back = get_entry(table_base, table->private->underflow[hook]);
396 (*pskb)->nfcache |= e->nfcache;
397 if (ip6_packet_match(*pskb, ipv6, indev, outdev,
399 struct ip6t_entry_target *t;
401 if (IP6T_MATCH_ITERATE(e, do_match,
404 datalen, &hotdrop) != 0)
407 ADD_COUNTER(e->counters, ntohs(ipv6->payload_len) + IPV6_HDR_LEN, 1);
409 t = ip6t_get_target(e);
410 IP_NF_ASSERT(t->u.kernel.target);
411 /* Standard target? */
412 if (!t->u.kernel.target->target) {
415 v = ((struct ip6t_standard_target *)t)->verdict;
417 /* Pop from stack? */
418 if (v != IP6T_RETURN) {
419 verdict = (unsigned)(-v) - 1;
423 back = get_entry(table_base,
428 != (void *)e + e->next_offset) {
429 /* Save old back ptr in next entry */
430 struct ip6t_entry *next
431 = (void *)e + e->next_offset;
433 = (void *)back - table_base;
434 /* set back pointer to next entry */
438 e = get_entry(table_base, v);
440 /* Targets which reenter must return
442 #ifdef CONFIG_NETFILTER_DEBUG
443 ((struct ip6t_entry *)table_base)->comefrom
446 verdict = t->u.kernel.target->target(pskb,
452 #ifdef CONFIG_NETFILTER_DEBUG
453 if (((struct ip6t_entry *)table_base)->comefrom
455 && verdict == IP6T_CONTINUE) {
456 printk("Target %s reentered!\n",
457 t->u.kernel.target->name);
460 ((struct ip6t_entry *)table_base)->comefrom
463 /* Target might have changed stuff. */
464 ipv6 = (*pskb)->nh.ipv6h;
465 protohdr = (u_int32_t *)((void *)ipv6 + IPV6_HDR_LEN);
466 datalen = (*pskb)->len - IPV6_HDR_LEN;
468 if (verdict == IP6T_CONTINUE)
469 e = (void *)e + e->next_offset;
477 e = (void *)e + e->next_offset;
481 #ifdef CONFIG_NETFILTER_DEBUG
482 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
484 read_unlock_bh(&table->lock);
486 #ifdef DEBUG_ALLOW_ALL
495 /* If it succeeds, returns element and locks mutex */
497 find_inlist_lock_noload(struct list_head *head,
500 struct semaphore *mutex)
505 duprintf("find_inlist: searching for `%s' in %s.\n",
506 name, head == &ip6t_target ? "ip6t_target"
507 : head == &ip6t_match ? "ip6t_match"
508 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
511 *error = down_interruptible(mutex);
515 ret = list_named_find(head, name);
524 #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m))
527 find_inlist_lock(struct list_head *head,
531 struct semaphore *mutex)
535 ret = find_inlist_lock_noload(head, name, error, mutex);
537 duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
538 request_module("%s%s", prefix, name);
539 ret = find_inlist_lock_noload(head, name, error, mutex);
546 static inline struct ip6t_table *
547 find_table_lock(const char *name, int *error, struct semaphore *mutex)
549 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex);
552 static inline struct ip6t_match *
553 find_match_lock(const char *name, int *error, struct semaphore *mutex)
555 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex);
558 static inline struct ip6t_target *
559 find_target_lock(const char *name, int *error, struct semaphore *mutex)
561 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex);
564 /* All zeroes == unconditional rule. */
566 unconditional(const struct ip6t_ip6 *ipv6)
570 for (i = 0; i < sizeof(*ipv6); i++)
571 if (((char *)ipv6)[i])
574 return (i == sizeof(*ipv6));
577 /* Figures out from what hook each rule can be called: returns 0 if
578 there are loops. Puts hook bitmask in comefrom. */
580 mark_source_chains(struct ip6t_table_info *newinfo, unsigned int valid_hooks)
584 /* No recursion; use packet counter to save back ptrs (reset
585 to 0 as we leave), and comefrom to save source hook bitmask */
586 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
587 unsigned int pos = newinfo->hook_entry[hook];
589 = (struct ip6t_entry *)(newinfo->entries + pos);
591 if (!(valid_hooks & (1 << hook)))
594 /* Set initial back pointer. */
595 e->counters.pcnt = pos;
598 struct ip6t_standard_target *t
599 = (void *)ip6t_get_target(e);
601 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
602 printk("iptables: loop hook %u pos %u %08X.\n",
603 hook, pos, e->comefrom);
607 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
609 /* Unconditional return/END. */
610 if (e->target_offset == sizeof(struct ip6t_entry)
611 && (strcmp(t->target.u.user.name,
612 IP6T_STANDARD_TARGET) == 0)
614 && unconditional(&e->ipv6)) {
615 unsigned int oldpos, size;
617 /* Return: backtrack through the last
620 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
621 #ifdef DEBUG_IP_FIREWALL_USER
623 & (1 << NF_IP6_NUMHOOKS)) {
624 duprintf("Back unset "
631 pos = e->counters.pcnt;
632 e->counters.pcnt = 0;
634 /* We're at the start. */
638 e = (struct ip6t_entry *)
639 (newinfo->entries + pos);
640 } while (oldpos == pos + e->next_offset);
643 size = e->next_offset;
644 e = (struct ip6t_entry *)
645 (newinfo->entries + pos + size);
646 e->counters.pcnt = pos;
649 int newpos = t->verdict;
651 if (strcmp(t->target.u.user.name,
652 IP6T_STANDARD_TARGET) == 0
654 /* This a jump; chase it. */
655 duprintf("Jump rule %u -> %u\n",
658 /* ... this is a fallthru */
659 newpos = pos + e->next_offset;
661 e = (struct ip6t_entry *)
662 (newinfo->entries + newpos);
663 e->counters.pcnt = pos;
668 duprintf("Finished chain %u\n", hook);
674 cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
676 if (i && (*i)-- == 0)
679 if (m->u.kernel.match->destroy)
680 m->u.kernel.match->destroy(m->data,
681 m->u.match_size - sizeof(*m));
682 module_put(m->u.kernel.match->me);
687 standard_check(const struct ip6t_entry_target *t,
688 unsigned int max_offset)
690 struct ip6t_standard_target *targ = (void *)t;
692 /* Check standard info. */
694 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
695 duprintf("standard_check: target size %u != %u\n",
697 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
701 if (targ->verdict >= 0
702 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
703 duprintf("ip6t_standard_check: bad verdict (%i)\n",
708 if (targ->verdict < -NF_MAX_VERDICT - 1) {
709 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
717 check_match(struct ip6t_entry_match *m,
719 const struct ip6t_ip6 *ipv6,
720 unsigned int hookmask,
724 struct ip6t_match *match;
726 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex);
728 // duprintf("check_match: `%s' not found\n", m->u.name);
731 if (!try_module_get(match->me)) {
735 m->u.kernel.match = match;
738 if (m->u.kernel.match->checkentry
739 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
740 m->u.match_size - sizeof(*m),
742 module_put(m->u.kernel.match->me);
743 duprintf("ip_tables: check failed for `%s'.\n",
744 m->u.kernel.match->name);
752 static struct ip6t_target ip6t_standard_target;
755 check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
758 struct ip6t_entry_target *t;
759 struct ip6t_target *target;
763 if (!ip6_checkentry(&e->ipv6)) {
764 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
769 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
771 goto cleanup_matches;
773 t = ip6t_get_target(e);
774 target = find_target_lock(t->u.user.name, &ret, &ip6t_mutex);
776 duprintf("check_entry: `%s' not found\n", t->u.user.name);
777 goto cleanup_matches;
779 if (!try_module_get(target->me)) {
782 goto cleanup_matches;
784 t->u.kernel.target = target;
786 if (!t->u.kernel.target) {
788 goto cleanup_matches;
790 if (t->u.kernel.target == &ip6t_standard_target) {
791 if (!standard_check(t, size)) {
793 goto cleanup_matches;
795 } else if (t->u.kernel.target->checkentry
796 && !t->u.kernel.target->checkentry(name, e, t->data,
800 module_put(t->u.kernel.target->me);
801 duprintf("ip_tables: check failed for `%s'.\n",
802 t->u.kernel.target->name);
804 goto cleanup_matches;
811 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
816 check_entry_size_and_hooks(struct ip6t_entry *e,
817 struct ip6t_table_info *newinfo,
819 unsigned char *limit,
820 const unsigned int *hook_entries,
821 const unsigned int *underflows,
826 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
827 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
828 duprintf("Bad offset %p\n", e);
833 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
834 duprintf("checking: element %p size %u\n",
839 /* Check hooks & underflows */
840 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
841 if ((unsigned char *)e - base == hook_entries[h])
842 newinfo->hook_entry[h] = hook_entries[h];
843 if ((unsigned char *)e - base == underflows[h])
844 newinfo->underflow[h] = underflows[h];
847 /* FIXME: underflows must be unconditional, standard verdicts
848 < 0 (not IP6T_RETURN). --RR */
850 /* Clear counters and comefrom */
851 e->counters = ((struct ip6t_counters) { 0, 0 });
859 cleanup_entry(struct ip6t_entry *e, unsigned int *i)
861 struct ip6t_entry_target *t;
863 if (i && (*i)-- == 0)
866 /* Cleanup all matches */
867 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
868 t = ip6t_get_target(e);
869 if (t->u.kernel.target->destroy)
870 t->u.kernel.target->destroy(t->data,
871 t->u.target_size - sizeof(*t));
872 module_put(t->u.kernel.target->me);
876 /* Checks and translates the user-supplied table segment (held in
879 translate_table(const char *name,
880 unsigned int valid_hooks,
881 struct ip6t_table_info *newinfo,
884 const unsigned int *hook_entries,
885 const unsigned int *underflows)
890 newinfo->size = size;
891 newinfo->number = number;
893 /* Init all hooks to impossible value. */
894 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
895 newinfo->hook_entry[i] = 0xFFFFFFFF;
896 newinfo->underflow[i] = 0xFFFFFFFF;
899 duprintf("translate_table: size %u\n", newinfo->size);
901 /* Walk through entries, checking offsets. */
902 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
903 check_entry_size_and_hooks,
906 newinfo->entries + size,
907 hook_entries, underflows, &i);
912 duprintf("translate_table: %u not %u entries\n",
917 /* Check hooks all assigned */
918 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
919 /* Only hooks which are valid */
920 if (!(valid_hooks & (1 << i)))
922 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
923 duprintf("Invalid hook entry %u %u\n",
927 if (newinfo->underflow[i] == 0xFFFFFFFF) {
928 duprintf("Invalid underflow %u %u\n",
934 if (!mark_source_chains(newinfo, valid_hooks))
937 /* Finally, each sanity check must pass */
939 ret = IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
940 check_entry, name, size, &i);
943 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size,
948 /* And one copy for every other CPU */
949 for (i = 1; i < NR_CPUS; i++) {
950 memcpy(newinfo->entries + SMP_ALIGN(newinfo->size)*i,
952 SMP_ALIGN(newinfo->size));
958 static struct ip6t_table_info *
959 replace_table(struct ip6t_table *table,
960 unsigned int num_counters,
961 struct ip6t_table_info *newinfo,
964 struct ip6t_table_info *oldinfo;
966 #ifdef CONFIG_NETFILTER_DEBUG
968 struct ip6t_entry *table_base;
971 for (i = 0; i < NR_CPUS; i++) {
973 (void *)newinfo->entries
974 + TABLE_OFFSET(newinfo, i);
976 table_base->comefrom = 0xdead57ac;
981 /* Do the substitution. */
982 write_lock_bh(&table->lock);
983 /* Check inside lock: is the old number correct? */
984 if (num_counters != table->private->number) {
985 duprintf("num_counters != table->private->number (%u/%u)\n",
986 num_counters, table->private->number);
987 write_unlock_bh(&table->lock);
991 oldinfo = table->private;
992 table->private = newinfo;
993 newinfo->initial_entries = oldinfo->initial_entries;
994 write_unlock_bh(&table->lock);
1001 add_entry_to_counter(const struct ip6t_entry *e,
1002 struct ip6t_counters total[],
1005 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1012 get_counters(const struct ip6t_table_info *t,
1013 struct ip6t_counters counters[])
1018 for (cpu = 0; cpu < NR_CPUS; cpu++) {
1020 IP6T_ENTRY_ITERATE(t->entries + TABLE_OFFSET(t, cpu),
1022 add_entry_to_counter,
1029 copy_entries_to_user(unsigned int total_size,
1030 struct ip6t_table *table,
1033 unsigned int off, num, countersize;
1034 struct ip6t_entry *e;
1035 struct ip6t_counters *counters;
1038 /* We need atomic snapshot of counters: rest doesn't change
1039 (other than comefrom, which userspace doesn't care
1041 countersize = sizeof(struct ip6t_counters) * table->private->number;
1042 counters = vmalloc(countersize);
1044 if (counters == NULL)
1047 /* First, sum counters... */
1048 memset(counters, 0, countersize);
1049 write_lock_bh(&table->lock);
1050 get_counters(table->private, counters);
1051 write_unlock_bh(&table->lock);
1053 /* ... then copy entire thing from CPU 0... */
1054 if (copy_to_user(userptr, table->private->entries, total_size) != 0) {
1059 /* FIXME: use iterator macros --RR */
1060 /* ... then go back and fix counters and names */
1061 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1063 struct ip6t_entry_match *m;
1064 struct ip6t_entry_target *t;
1066 e = (struct ip6t_entry *)(table->private->entries + off);
1067 if (copy_to_user(userptr + off
1068 + offsetof(struct ip6t_entry, counters),
1070 sizeof(counters[num])) != 0) {
1075 for (i = sizeof(struct ip6t_entry);
1076 i < e->target_offset;
1077 i += m->u.match_size) {
1080 if (copy_to_user(userptr + off + i
1081 + offsetof(struct ip6t_entry_match,
1083 m->u.kernel.match->name,
1084 strlen(m->u.kernel.match->name)+1)
1091 t = ip6t_get_target(e);
1092 if (copy_to_user(userptr + off + e->target_offset
1093 + offsetof(struct ip6t_entry_target,
1095 t->u.kernel.target->name,
1096 strlen(t->u.kernel.target->name)+1) != 0) {
1108 get_entries(const struct ip6t_get_entries *entries,
1109 struct ip6t_get_entries *uptr)
1112 struct ip6t_table *t;
1114 t = find_table_lock(entries->name, &ret, &ip6t_mutex);
1116 duprintf("t->private->number = %u\n",
1117 t->private->number);
1118 if (entries->size == t->private->size)
1119 ret = copy_entries_to_user(t->private->size,
1120 t, uptr->entrytable);
1122 duprintf("get_entries: I've got %u not %u!\n",
1129 duprintf("get_entries: Can't find %s!\n",
1136 do_replace(void *user, unsigned int len)
1139 struct ip6t_replace tmp;
1140 struct ip6t_table *t;
1141 struct ip6t_table_info *newinfo, *oldinfo;
1142 struct ip6t_counters *counters;
1144 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1147 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1148 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1151 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1152 + SMP_ALIGN(tmp.size) * NR_CPUS);
1156 if (copy_from_user(newinfo->entries, user + sizeof(tmp),
1162 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1167 memset(counters, 0, tmp.num_counters * sizeof(struct ip6t_counters));
1169 ret = translate_table(tmp.name, tmp.valid_hooks,
1170 newinfo, tmp.size, tmp.num_entries,
1171 tmp.hook_entry, tmp.underflow);
1173 goto free_newinfo_counters;
1175 duprintf("ip_tables: Translated table\n");
1177 t = find_table_lock(tmp.name, &ret, &ip6t_mutex);
1179 goto free_newinfo_counters_untrans;
1182 if (tmp.valid_hooks != t->valid_hooks) {
1183 duprintf("Valid hook crap: %08X vs %08X\n",
1184 tmp.valid_hooks, t->valid_hooks);
1186 goto free_newinfo_counters_untrans_unlock;
1189 /* Get a reference in advance, we're not allowed fail later */
1190 if (!try_module_get(t->me)) {
1192 goto free_newinfo_counters_untrans_unlock;
1195 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1199 /* Update module usage count based on number of rules */
1200 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1201 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1202 if ((oldinfo->number > oldinfo->initial_entries) ||
1203 (newinfo->number <= oldinfo->initial_entries))
1205 if ((oldinfo->number > oldinfo->initial_entries) &&
1206 (newinfo->number <= oldinfo->initial_entries))
1209 /* Get the old counters. */
1210 get_counters(oldinfo, counters);
1211 /* Decrease module usage counts and free resource */
1212 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1214 /* Silent error: too late now. */
1215 copy_to_user(tmp.counters, counters,
1216 sizeof(struct ip6t_counters) * tmp.num_counters);
1223 free_newinfo_counters_untrans_unlock:
1225 free_newinfo_counters_untrans:
1226 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
1227 free_newinfo_counters:
1234 /* We're lazy, and add to the first CPU; overflow works its fey magic
1235 * and everything is OK. */
1237 add_counter_to_entry(struct ip6t_entry *e,
1238 const struct ip6t_counters addme[],
1242 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1244 (long unsigned int)e->counters.pcnt,
1245 (long unsigned int)e->counters.bcnt,
1246 (long unsigned int)addme[*i].pcnt,
1247 (long unsigned int)addme[*i].bcnt);
1250 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1257 do_add_counters(void *user, unsigned int len)
1260 struct ip6t_counters_info tmp, *paddc;
1261 struct ip6t_table *t;
1264 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1267 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1270 paddc = vmalloc(len);
1274 if (copy_from_user(paddc, user, len) != 0) {
1279 t = find_table_lock(tmp.name, &ret, &ip6t_mutex);
1283 write_lock_bh(&t->lock);
1284 if (t->private->number != paddc->num_counters) {
1286 goto unlock_up_free;
1290 IP6T_ENTRY_ITERATE(t->private->entries,
1292 add_counter_to_entry,
1296 write_unlock_bh(&t->lock);
1305 do_ip6t_set_ctl(struct sock *sk, int cmd, void *user, unsigned int len)
1309 if (!capable(CAP_NET_ADMIN))
1313 case IP6T_SO_SET_REPLACE:
1314 ret = do_replace(user, len);
1317 case IP6T_SO_SET_ADD_COUNTERS:
1318 ret = do_add_counters(user, len);
1322 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1330 do_ip6t_get_ctl(struct sock *sk, int cmd, void *user, int *len)
1334 if (!capable(CAP_NET_ADMIN))
1338 case IP6T_SO_GET_INFO: {
1339 char name[IP6T_TABLE_MAXNAMELEN];
1340 struct ip6t_table *t;
1342 if (*len != sizeof(struct ip6t_getinfo)) {
1343 duprintf("length %u != %u\n", *len,
1344 sizeof(struct ip6t_getinfo));
1349 if (copy_from_user(name, user, sizeof(name)) != 0) {
1353 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1354 t = find_table_lock(name, &ret, &ip6t_mutex);
1356 struct ip6t_getinfo info;
1358 info.valid_hooks = t->valid_hooks;
1359 memcpy(info.hook_entry, t->private->hook_entry,
1360 sizeof(info.hook_entry));
1361 memcpy(info.underflow, t->private->underflow,
1362 sizeof(info.underflow));
1363 info.num_entries = t->private->number;
1364 info.size = t->private->size;
1365 strcpy(info.name, name);
1367 if (copy_to_user(user, &info, *len) != 0)
1377 case IP6T_SO_GET_ENTRIES: {
1378 struct ip6t_get_entries get;
1380 if (*len < sizeof(get)) {
1381 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1383 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1385 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1386 duprintf("get_entries: %u != %u\n", *len,
1387 sizeof(struct ip6t_get_entries) + get.size);
1390 ret = get_entries(&get, user);
1395 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1402 /* Registration hooks for targets. */
1404 ip6t_register_target(struct ip6t_target *target)
1408 ret = down_interruptible(&ip6t_mutex);
1412 if (!list_named_insert(&ip6t_target, target)) {
1413 duprintf("ip6t_register_target: `%s' already in list!\n",
1422 ip6t_unregister_target(struct ip6t_target *target)
1425 LIST_DELETE(&ip6t_target, target);
1430 ip6t_register_match(struct ip6t_match *match)
1434 ret = down_interruptible(&ip6t_mutex);
1438 if (!list_named_insert(&ip6t_match, match)) {
1439 duprintf("ip6t_register_match: `%s' already in list!\n",
1449 ip6t_unregister_match(struct ip6t_match *match)
1452 LIST_DELETE(&ip6t_match, match);
1456 int ip6t_register_table(struct ip6t_table *table)
1459 struct ip6t_table_info *newinfo;
1460 static struct ip6t_table_info bootstrap
1461 = { 0, 0, 0, { 0 }, { 0 }, { } };
1463 newinfo = vmalloc(sizeof(struct ip6t_table_info)
1464 + SMP_ALIGN(table->table->size) * NR_CPUS);
1468 memcpy(newinfo->entries, table->table->entries, table->table->size);
1470 ret = translate_table(table->name, table->valid_hooks,
1471 newinfo, table->table->size,
1472 table->table->num_entries,
1473 table->table->hook_entry,
1474 table->table->underflow);
1480 ret = down_interruptible(&ip6t_mutex);
1486 /* Don't autoload: we'd eat our tail... */
1487 if (list_named_find(&ip6t_tables, table->name)) {
1492 /* Simplifies replace_table code. */
1493 table->private = &bootstrap;
1494 if (!replace_table(table, 0, newinfo, &ret))
1497 duprintf("table->private->number = %u\n",
1498 table->private->number);
1500 /* save number of initial entries */
1501 table->private->initial_entries = table->private->number;
1503 table->lock = RW_LOCK_UNLOCKED;
1504 list_prepend(&ip6t_tables, table);
1515 void ip6t_unregister_table(struct ip6t_table *table)
1518 LIST_DELETE(&ip6t_tables, table);
1521 /* Decrease module usage counts and free resources */
1522 IP6T_ENTRY_ITERATE(table->private->entries, table->private->size,
1523 cleanup_entry, NULL);
1524 vfree(table->private);
1527 /* Returns 1 if the port is matched by the range, 0 otherwise */
1529 port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1533 ret = (port >= min && port <= max) ^ invert;
1538 tcp_find_option(u_int8_t option,
1539 const struct tcphdr *tcp,
1544 unsigned int i = sizeof(struct tcphdr);
1545 const u_int8_t *opt = (u_int8_t *)tcp;
1547 duprintf("tcp_match: finding option\n");
1548 /* If we don't have the whole header, drop packet. */
1549 if (tcp->doff * 4 < sizeof(struct tcphdr) ||
1550 tcp->doff * 4 > datalen) {
1555 while (i < tcp->doff * 4) {
1556 if (opt[i] == option) return !invert;
1557 if (opt[i] < 2) i++;
1558 else i += opt[i+1]?:1;
1565 tcp_match(const struct sk_buff *skb,
1566 const struct net_device *in,
1567 const struct net_device *out,
1568 const void *matchinfo,
1574 const struct tcphdr *tcp;
1575 const struct ip6t_tcp *tcpinfo = matchinfo;
1577 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1581 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1582 causes this. Its a cracker trying to break in by doing a
1583 flag overwrite to pass the direction checks.
1587 duprintf("Dropping evil TCP offset=1 frag.\n");
1590 } else if (offset == 0 && datalen < sizeof(struct tcphdr)) {
1591 /* We've been asked to examine this packet, and we
1592 can't. Hence, no choice but to drop. */
1593 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1598 tcpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1599 tcpoff = ipv6_skip_exthdr(skb, tcpoff, &nexthdr, skb->len - tcpoff);
1600 if (tcpoff < 0 || tcpoff > skb->len) {
1601 duprintf("tcp_match: cannot skip exthdr. Dropping.\n");
1604 } else if (nexthdr == IPPROTO_FRAGMENT)
1606 else if (nexthdr != IPPROTO_TCP ||
1607 skb->len - tcpoff < sizeof(struct tcphdr)) {
1608 /* cannot be occured */
1609 duprintf("tcp_match: cannot get TCP header. Dropping.\n");
1614 tcp = (struct tcphdr *)(skb->data + tcpoff);
1616 /* FIXME: Try tcp doff >> packet len against various stacks --RR */
1618 #define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1620 /* Must not be a fragment. */
1622 && port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1624 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT))
1625 && port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1627 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT))
1628 && FWINVTCP((((unsigned char *)tcp)[13]
1629 & tcpinfo->flg_mask)
1630 == tcpinfo->flg_cmp,
1632 && (!tcpinfo->option
1633 || tcp_find_option(tcpinfo->option, tcp, datalen,
1635 & IP6T_TCP_INV_OPTION,
1639 /* Called when user tries to insert an entry of this type. */
1641 tcp_checkentry(const char *tablename,
1642 const struct ip6t_ip6 *ipv6,
1644 unsigned int matchsize,
1645 unsigned int hook_mask)
1647 const struct ip6t_tcp *tcpinfo = matchinfo;
1649 /* Must specify proto == TCP, and no unknown invflags */
1650 return ipv6->proto == IPPROTO_TCP
1651 && !(ipv6->invflags & IP6T_INV_PROTO)
1652 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1653 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1657 udp_match(const struct sk_buff *skb,
1658 const struct net_device *in,
1659 const struct net_device *out,
1660 const void *matchinfo,
1666 const struct udphdr *udp;
1667 const struct ip6t_udp *udpinfo = matchinfo;
1669 u8 nexthdr = skb->nh.ipv6h->nexthdr;
1671 if (offset == 0 && datalen < sizeof(struct udphdr)) {
1672 /* We've been asked to examine this packet, and we
1673 can't. Hence, no choice but to drop. */
1674 duprintf("Dropping evil UDP tinygram.\n");
1679 udpoff = (u8*)(skb->nh.ipv6h + 1) - skb->data;
1680 udpoff = ipv6_skip_exthdr(skb, udpoff, &nexthdr, skb->len - udpoff);
1681 if (udpoff < 0 || udpoff > skb->len) {
1682 duprintf("udp_match: cannot skip exthdr. Dropping.\n");
1685 } else if (nexthdr == IPPROTO_FRAGMENT)
1687 else if (nexthdr != IPPROTO_UDP ||
1688 skb->len - udpoff < sizeof(struct udphdr)) {
1689 duprintf("udp_match: cannot get UDP header. Dropping.\n");
1694 udp = (struct udphdr *)(skb->data + udpoff);
1696 /* Must not be a fragment. */
1698 && port_match(udpinfo->spts[0], udpinfo->spts[1],
1700 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1701 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1703 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1706 /* Called when user tries to insert an entry of this type. */
1708 udp_checkentry(const char *tablename,
1709 const struct ip6t_ip6 *ipv6,
1711 unsigned int matchinfosize,
1712 unsigned int hook_mask)
1714 const struct ip6t_udp *udpinfo = matchinfo;
1716 /* Must specify proto == UDP, and no unknown invflags */
1717 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1718 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1722 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1723 duprintf("ip6t_udp: matchsize %u != %u\n",
1724 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1727 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1728 duprintf("ip6t_udp: unknown flags %X\n",
1736 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1738 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1739 u_int8_t type, u_int8_t code,
1742 return (type == test_type && code >= min_code && code <= max_code)
1747 icmp6_match(const struct sk_buff *skb,
1748 const struct net_device *in,
1749 const struct net_device *out,
1750 const void *matchinfo,
1756 const struct icmp6hdr *icmp = hdr;
1757 const struct ip6t_icmp *icmpinfo = matchinfo;
1759 if (offset == 0 && datalen < 2) {
1760 /* We've been asked to examine this packet, and we
1761 can't. Hence, no choice but to drop. */
1762 duprintf("Dropping evil ICMP tinygram.\n");
1767 /* Must not be a fragment. */
1769 && icmp6_type_code_match(icmpinfo->type,
1772 icmp->icmp6_type, icmp->icmp6_code,
1773 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1776 /* Called when user tries to insert an entry of this type. */
1778 icmp6_checkentry(const char *tablename,
1779 const struct ip6t_ip6 *ipv6,
1781 unsigned int matchsize,
1782 unsigned int hook_mask)
1784 const struct ip6t_icmp *icmpinfo = matchinfo;
1786 /* Must specify proto == ICMP, and no unknown invflags */
1787 return ipv6->proto == IPPROTO_ICMPV6
1788 && !(ipv6->invflags & IP6T_INV_PROTO)
1789 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1790 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1793 /* The built-in targets: standard (NULL) and error. */
1794 static struct ip6t_target ip6t_standard_target = {
1795 .name = IP6T_STANDARD_TARGET,
1798 static struct ip6t_target ip6t_error_target = {
1799 .name = IP6T_ERROR_TARGET,
1800 .target = ip6t_error,
1803 static struct nf_sockopt_ops ip6t_sockopts = {
1805 .set_optmin = IP6T_BASE_CTL,
1806 .set_optmax = IP6T_SO_SET_MAX+1,
1807 .set = do_ip6t_set_ctl,
1808 .get_optmin = IP6T_BASE_CTL,
1809 .get_optmax = IP6T_SO_GET_MAX+1,
1810 .get = do_ip6t_get_ctl,
1813 static struct ip6t_match tcp_matchstruct = {
1815 .match = &tcp_match,
1816 .checkentry = &tcp_checkentry,
1819 static struct ip6t_match udp_matchstruct = {
1821 .match = &udp_match,
1822 .checkentry = &udp_checkentry,
1825 static struct ip6t_match icmp6_matchstruct = {
1827 .match = &icmp6_match,
1828 .checkentry = &icmp6_checkentry,
1831 #ifdef CONFIG_PROC_FS
1832 static inline int print_name(const char *i,
1833 off_t start_offset, char *buffer, int length,
1834 off_t *pos, unsigned int *count)
1836 if ((*count)++ >= start_offset) {
1837 unsigned int namelen;
1839 namelen = sprintf(buffer + *pos, "%s\n",
1840 i + sizeof(struct list_head));
1841 if (*pos + namelen > length) {
1842 /* Stop iterating */
1850 static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1853 unsigned int count = 0;
1855 if (down_interruptible(&ip6t_mutex) != 0)
1858 LIST_FIND(&ip6t_tables, print_name, char *,
1859 offset, buffer, length, &pos, &count);
1863 /* `start' hack - see fs/proc/generic.c line ~105 */
1864 *start=(char *)((unsigned long)count-offset);
1868 static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
1871 unsigned int count = 0;
1873 if (down_interruptible(&ip6t_mutex) != 0)
1876 LIST_FIND(&ip6t_target, print_name, char *,
1877 offset, buffer, length, &pos, &count);
1881 *start = (char *)((unsigned long)count - offset);
1885 static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
1888 unsigned int count = 0;
1890 if (down_interruptible(&ip6t_mutex) != 0)
1893 LIST_FIND(&ip6t_match, print_name, char *,
1894 offset, buffer, length, &pos, &count);
1898 *start = (char *)((unsigned long)count - offset);
1902 static struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1903 { { "ip6_tables_names", ip6t_get_tables },
1904 { "ip6_tables_targets", ip6t_get_targets },
1905 { "ip6_tables_matches", ip6t_get_matches },
1907 #endif /*CONFIG_PROC_FS*/
1909 static int __init init(void)
1913 /* Noone else will be downing sem now, so we won't sleep */
1915 list_append(&ip6t_target, &ip6t_standard_target);
1916 list_append(&ip6t_target, &ip6t_error_target);
1917 list_append(&ip6t_match, &tcp_matchstruct);
1918 list_append(&ip6t_match, &udp_matchstruct);
1919 list_append(&ip6t_match, &icmp6_matchstruct);
1922 /* Register setsockopt */
1923 ret = nf_register_sockopt(&ip6t_sockopts);
1925 duprintf("Unable to register sockopts.\n");
1929 #ifdef CONFIG_PROC_FS
1931 struct proc_dir_entry *proc;
1934 for (i = 0; ip6t_proc_entry[i].name; i++) {
1935 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
1936 ip6t_proc_entry[i].get_info);
1939 proc_net_remove(ip6t_proc_entry[i].name);
1940 nf_unregister_sockopt(&ip6t_sockopts);
1943 proc->owner = THIS_MODULE;
1948 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
1952 static void __exit fini(void)
1954 nf_unregister_sockopt(&ip6t_sockopts);
1955 #ifdef CONFIG_PROC_FS
1958 for (i = 0; ip6t_proc_entry[i].name; i++)
1959 proc_net_remove(ip6t_proc_entry[i].name);
1964 EXPORT_SYMBOL(ip6t_register_table);
1965 EXPORT_SYMBOL(ip6t_unregister_table);
1966 EXPORT_SYMBOL(ip6t_do_table);
1967 EXPORT_SYMBOL(ip6t_register_match);
1968 EXPORT_SYMBOL(ip6t_unregister_match);
1969 EXPORT_SYMBOL(ip6t_register_target);
1970 EXPORT_SYMBOL(ip6t_unregister_target);
1971 EXPORT_SYMBOL(ip6t_ext_hdr);