[NETFILTER]: Call POST_ROUTING hook before fragmentation
[linux-2.6-block.git] / net / ipv6 / netfilter / ip6_tables.c
CommitLineData
1da177e4
LT
1/*
2 * Packet matching code.
3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
6b7d31fc 5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
1da177e4
LT
6 *
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.
10 *
11 * 19 Jan 2002 Harald Welte <laforge@gnumonks.org>
12 * - increase module usage count as soon as we have rules inside
13 * a table
14 * 06 Jun 2002 Andras Kis-Szabo <kisza@sch.bme.hu>
15 * - new extension header parser code
16 */
17#include <linux/config.h>
14c85021 18#include <linux/in.h>
1da177e4
LT
19#include <linux/skbuff.h>
20#include <linux/kmod.h>
21#include <linux/vmalloc.h>
22#include <linux/netdevice.h>
23#include <linux/module.h>
24#include <linux/tcp.h>
25#include <linux/udp.h>
26#include <linux/icmpv6.h>
1da177e4
LT
27#include <net/ipv6.h>
28#include <asm/uaccess.h>
29#include <asm/semaphore.h>
30#include <linux/proc_fs.h>
c8923c6b 31#include <linux/cpumask.h>
1da177e4
LT
32
33#include <linux/netfilter_ipv6/ip6_tables.h>
34
35MODULE_LICENSE("GPL");
36MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
37MODULE_DESCRIPTION("IPv6 packet filter");
38
39#define IPV6_HDR_LEN (sizeof(struct ipv6hdr))
40#define IPV6_OPTHDR_LEN (sizeof(struct ipv6_opt_hdr))
41
42/*#define DEBUG_IP_FIREWALL*/
43/*#define DEBUG_ALLOW_ALL*/ /* Useful for remote debugging */
44/*#define DEBUG_IP_FIREWALL_USER*/
45
46#ifdef DEBUG_IP_FIREWALL
47#define dprintf(format, args...) printk(format , ## args)
48#else
49#define dprintf(format, args...)
50#endif
51
52#ifdef DEBUG_IP_FIREWALL_USER
53#define duprintf(format, args...) printk(format , ## args)
54#else
55#define duprintf(format, args...)
56#endif
57
58#ifdef CONFIG_NETFILTER_DEBUG
59#define IP_NF_ASSERT(x) \
60do { \
61 if (!(x)) \
62 printk("IP_NF_ASSERT: %s:%s:%u\n", \
63 __FUNCTION__, __FILE__, __LINE__); \
64} while(0)
65#else
66#define IP_NF_ASSERT(x)
67#endif
68#define SMP_ALIGN(x) (((x) + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1))
69
70static DECLARE_MUTEX(ip6t_mutex);
71
72/* Must have 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)
1da177e4
LT
75#include <linux/netfilter_ipv4/listhelp.h>
76
77#if 0
78/* All the better to debug you with... */
79#define static
80#define inline
81#endif
82
6b7d31fc 83/*
1da177e4 84 We keep a set of rules for each CPU, so we can avoid write-locking
6b7d31fc
HW
85 them in the softirq when updating the counters and therefore
86 only need to read-lock in the softirq; doing a write_lock_bh() in user
87 context stops packets coming through and allows user context to read
88 the counters or update the rules.
1da177e4 89
1da177e4
LT
90 Hence the start of any table is given by get_table() below. */
91
92/* The table itself */
93struct ip6t_table_info
94{
95 /* Size per table */
96 unsigned int size;
97 /* Number of entries: FIXME. --RR */
98 unsigned int number;
99 /* Initial number of entries. Needed for module usage count */
100 unsigned int initial_entries;
101
102 /* Entry points and underflows */
103 unsigned int hook_entry[NF_IP6_NUMHOOKS];
104 unsigned int underflow[NF_IP6_NUMHOOKS];
105
106 /* ip6t_entry tables: one per CPU */
31836064 107 void *entries[NR_CPUS];
1da177e4
LT
108};
109
110static LIST_HEAD(ip6t_target);
111static LIST_HEAD(ip6t_match);
112static LIST_HEAD(ip6t_tables);
31836064 113#define SET_COUNTER(c,b,p) do { (c).bcnt = (b); (c).pcnt = (p); } while(0)
1da177e4
LT
114#define ADD_COUNTER(c,b,p) do { (c).bcnt += (b); (c).pcnt += (p); } while(0)
115
1da177e4
LT
116#if 0
117#define down(x) do { printk("DOWN:%u:" #x "\n", __LINE__); down(x); } while(0)
118#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; })
119#define up(x) do { printk("UP:%u:" #x "\n", __LINE__); up(x); } while(0)
120#endif
121
122static int ip6_masked_addrcmp(struct in6_addr addr1, struct in6_addr mask,
123 struct in6_addr addr2)
124{
125 int i;
126 for( i = 0; i < 16; i++){
127 if((addr1.s6_addr[i] & mask.s6_addr[i]) !=
128 (addr2.s6_addr[i] & mask.s6_addr[i]))
129 return 1;
130 }
131 return 0;
132}
133
134/* Check for an extension */
135int
136ip6t_ext_hdr(u8 nexthdr)
137{
138 return ( (nexthdr == IPPROTO_HOPOPTS) ||
139 (nexthdr == IPPROTO_ROUTING) ||
140 (nexthdr == IPPROTO_FRAGMENT) ||
141 (nexthdr == IPPROTO_ESP) ||
142 (nexthdr == IPPROTO_AH) ||
143 (nexthdr == IPPROTO_NONE) ||
144 (nexthdr == IPPROTO_DSTOPTS) );
145}
146
147/* Returns whether matches rule or not. */
148static inline int
149ip6_packet_match(const struct sk_buff *skb,
150 const char *indev,
151 const char *outdev,
152 const struct ip6t_ip6 *ip6info,
153 unsigned int *protoff,
154 int *fragoff)
155{
156 size_t i;
157 unsigned long ret;
158 const struct ipv6hdr *ipv6 = skb->nh.ipv6h;
159
160#define FWINV(bool,invflg) ((bool) ^ !!(ip6info->invflags & invflg))
161
162 if (FWINV(ip6_masked_addrcmp(ipv6->saddr,ip6info->smsk,ip6info->src),
163 IP6T_INV_SRCIP)
164 || FWINV(ip6_masked_addrcmp(ipv6->daddr,ip6info->dmsk,ip6info->dst),
165 IP6T_INV_DSTIP)) {
166 dprintf("Source or dest mismatch.\n");
167/*
168 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
169 ipinfo->smsk.s_addr, ipinfo->src.s_addr,
170 ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
171 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
172 ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
173 ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
174 return 0;
175 }
176
177 /* Look for ifname matches; this should unroll nicely. */
178 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
179 ret |= (((const unsigned long *)indev)[i]
180 ^ ((const unsigned long *)ip6info->iniface)[i])
181 & ((const unsigned long *)ip6info->iniface_mask)[i];
182 }
183
184 if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
185 dprintf("VIA in mismatch (%s vs %s).%s\n",
186 indev, ip6info->iniface,
187 ip6info->invflags&IP6T_INV_VIA_IN ?" (INV)":"");
188 return 0;
189 }
190
191 for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {
192 ret |= (((const unsigned long *)outdev)[i]
193 ^ ((const unsigned long *)ip6info->outiface)[i])
194 & ((const unsigned long *)ip6info->outiface_mask)[i];
195 }
196
197 if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
198 dprintf("VIA out mismatch (%s vs %s).%s\n",
199 outdev, ip6info->outiface,
200 ip6info->invflags&IP6T_INV_VIA_OUT ?" (INV)":"");
201 return 0;
202 }
203
204/* ... might want to do something with class and flowlabel here ... */
205
206 /* look for the desired protocol header */
207 if((ip6info->flags & IP6T_F_PROTO)) {
208 u_int8_t currenthdr = ipv6->nexthdr;
209 struct ipv6_opt_hdr _hdr, *hp;
210 u_int16_t ptr; /* Header offset in skb */
211 u_int16_t hdrlen; /* Header */
212 u_int16_t _fragoff = 0, *fp = NULL;
213
214 ptr = IPV6_HDR_LEN;
215
216 while (ip6t_ext_hdr(currenthdr)) {
217 /* Is there enough space for the next ext header? */
218 if (skb->len - ptr < IPV6_OPTHDR_LEN)
219 return 0;
220
221 /* NONE or ESP: there isn't protocol part */
222 /* If we want to count these packets in '-p all',
223 * we will change the return 0 to 1*/
224 if ((currenthdr == IPPROTO_NONE) ||
225 (currenthdr == IPPROTO_ESP))
226 break;
227
228 hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
229 BUG_ON(hp == NULL);
230
231 /* Size calculation */
232 if (currenthdr == IPPROTO_FRAGMENT) {
233 fp = skb_header_pointer(skb,
234 ptr+offsetof(struct frag_hdr,
235 frag_off),
236 sizeof(_fragoff),
237 &_fragoff);
238 if (fp == NULL)
239 return 0;
240
241 _fragoff = ntohs(*fp) & ~0x7;
242 hdrlen = 8;
243 } else if (currenthdr == IPPROTO_AH)
244 hdrlen = (hp->hdrlen+2)<<2;
245 else
246 hdrlen = ipv6_optlen(hp);
247
248 currenthdr = hp->nexthdr;
249 ptr += hdrlen;
250 /* ptr is too large */
251 if ( ptr > skb->len )
252 return 0;
253 if (_fragoff) {
254 if (ip6t_ext_hdr(currenthdr))
255 return 0;
256 break;
257 }
258 }
259
260 *protoff = ptr;
261 *fragoff = _fragoff;
262
263 /* currenthdr contains the protocol header */
264
265 dprintf("Packet protocol %hi ?= %s%hi.\n",
266 currenthdr,
267 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
268 ip6info->proto);
269
270 if (ip6info->proto == currenthdr) {
271 if(ip6info->invflags & IP6T_INV_PROTO) {
272 return 0;
273 }
274 return 1;
275 }
276
277 /* We need match for the '-p all', too! */
278 if ((ip6info->proto != 0) &&
279 !(ip6info->invflags & IP6T_INV_PROTO))
280 return 0;
281 }
282 return 1;
283}
284
285/* should be ip6 safe */
286static inline int
287ip6_checkentry(const struct ip6t_ip6 *ipv6)
288{
289 if (ipv6->flags & ~IP6T_F_MASK) {
290 duprintf("Unknown flag bits set: %08X\n",
291 ipv6->flags & ~IP6T_F_MASK);
292 return 0;
293 }
294 if (ipv6->invflags & ~IP6T_INV_MASK) {
295 duprintf("Unknown invflag bits set: %08X\n",
296 ipv6->invflags & ~IP6T_INV_MASK);
297 return 0;
298 }
299 return 1;
300}
301
302static unsigned int
303ip6t_error(struct sk_buff **pskb,
304 const struct net_device *in,
305 const struct net_device *out,
306 unsigned int hooknum,
307 const void *targinfo,
308 void *userinfo)
309{
310 if (net_ratelimit())
311 printk("ip6_tables: error: `%s'\n", (char *)targinfo);
312
313 return NF_DROP;
314}
315
316static inline
317int do_match(struct ip6t_entry_match *m,
318 const struct sk_buff *skb,
319 const struct net_device *in,
320 const struct net_device *out,
321 int offset,
322 unsigned int protoff,
323 int *hotdrop)
324{
325 /* Stop iteration if it doesn't match */
326 if (!m->u.kernel.match->match(skb, in, out, m->data,
327 offset, protoff, hotdrop))
328 return 1;
329 else
330 return 0;
331}
332
333static inline struct ip6t_entry *
334get_entry(void *base, unsigned int offset)
335{
336 return (struct ip6t_entry *)(base + offset);
337}
338
339/* Returns one of the generic firewall policies, like NF_ACCEPT. */
340unsigned int
341ip6t_do_table(struct sk_buff **pskb,
342 unsigned int hook,
343 const struct net_device *in,
344 const struct net_device *out,
345 struct ip6t_table *table,
346 void *userdata)
347{
6b7d31fc 348 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
1da177e4
LT
349 int offset = 0;
350 unsigned int protoff = 0;
351 int hotdrop = 0;
352 /* Initializing verdict to NF_DROP keeps gcc happy. */
353 unsigned int verdict = NF_DROP;
354 const char *indev, *outdev;
355 void *table_base;
356 struct ip6t_entry *e, *back;
357
358 /* Initialization */
359 indev = in ? in->name : nulldevname;
360 outdev = out ? out->name : nulldevname;
1da177e4
LT
361 /* We handle fragments by dealing with the first fragment as
362 * if it was a normal packet. All other fragments are treated
363 * normally, except that they will NEVER match rules that ask
364 * things we don't know, ie. tcp syn flag or ports). If the
365 * rule is also a fragment-specific rule, non-fragments won't
366 * match it. */
367
368 read_lock_bh(&table->lock);
369 IP_NF_ASSERT(table->valid_hooks & (1 << hook));
31836064 370 table_base = (void *)table->private->entries[smp_processor_id()];
1da177e4
LT
371 e = get_entry(table_base, table->private->hook_entry[hook]);
372
373#ifdef CONFIG_NETFILTER_DEBUG
374 /* Check noone else using our table */
375 if (((struct ip6t_entry *)table_base)->comefrom != 0xdead57ac
376 && ((struct ip6t_entry *)table_base)->comefrom != 0xeeeeeeec) {
377 printk("ASSERT: CPU #%u, %s comefrom(%p) = %X\n",
378 smp_processor_id(),
379 table->name,
380 &((struct ip6t_entry *)table_base)->comefrom,
381 ((struct ip6t_entry *)table_base)->comefrom);
382 }
383 ((struct ip6t_entry *)table_base)->comefrom = 0x57acc001;
384#endif
385
386 /* For return from builtin chain */
387 back = get_entry(table_base, table->private->underflow[hook]);
388
389 do {
390 IP_NF_ASSERT(e);
391 IP_NF_ASSERT(back);
1da177e4
LT
392 if (ip6_packet_match(*pskb, indev, outdev, &e->ipv6,
393 &protoff, &offset)) {
394 struct ip6t_entry_target *t;
395
396 if (IP6T_MATCH_ITERATE(e, do_match,
397 *pskb, in, out,
398 offset, protoff, &hotdrop) != 0)
399 goto no_match;
400
401 ADD_COUNTER(e->counters,
402 ntohs((*pskb)->nh.ipv6h->payload_len)
403 + IPV6_HDR_LEN,
404 1);
405
406 t = ip6t_get_target(e);
407 IP_NF_ASSERT(t->u.kernel.target);
408 /* Standard target? */
409 if (!t->u.kernel.target->target) {
410 int v;
411
412 v = ((struct ip6t_standard_target *)t)->verdict;
413 if (v < 0) {
414 /* Pop from stack? */
415 if (v != IP6T_RETURN) {
416 verdict = (unsigned)(-v) - 1;
417 break;
418 }
419 e = back;
420 back = get_entry(table_base,
421 back->comefrom);
422 continue;
423 }
05465343
PM
424 if (table_base + v != (void *)e + e->next_offset
425 && !(e->ipv6.flags & IP6T_F_GOTO)) {
1da177e4
LT
426 /* Save old back ptr in next entry */
427 struct ip6t_entry *next
428 = (void *)e + e->next_offset;
429 next->comefrom
430 = (void *)back - table_base;
431 /* set back pointer to next entry */
432 back = next;
433 }
434
435 e = get_entry(table_base, v);
436 } else {
437 /* Targets which reenter must return
438 abs. verdicts */
439#ifdef CONFIG_NETFILTER_DEBUG
440 ((struct ip6t_entry *)table_base)->comefrom
441 = 0xeeeeeeec;
442#endif
443 verdict = t->u.kernel.target->target(pskb,
444 in, out,
445 hook,
446 t->data,
447 userdata);
448
449#ifdef CONFIG_NETFILTER_DEBUG
450 if (((struct ip6t_entry *)table_base)->comefrom
451 != 0xeeeeeeec
452 && verdict == IP6T_CONTINUE) {
453 printk("Target %s reentered!\n",
454 t->u.kernel.target->name);
455 verdict = NF_DROP;
456 }
457 ((struct ip6t_entry *)table_base)->comefrom
458 = 0x57acc001;
459#endif
460 if (verdict == IP6T_CONTINUE)
461 e = (void *)e + e->next_offset;
462 else
463 /* Verdict */
464 break;
465 }
466 } else {
467
468 no_match:
469 e = (void *)e + e->next_offset;
470 }
471 } while (!hotdrop);
472
473#ifdef CONFIG_NETFILTER_DEBUG
474 ((struct ip6t_entry *)table_base)->comefrom = 0xdead57ac;
475#endif
476 read_unlock_bh(&table->lock);
477
478#ifdef DEBUG_ALLOW_ALL
479 return NF_ACCEPT;
480#else
481 if (hotdrop)
482 return NF_DROP;
483 else return verdict;
484#endif
485}
486
6b7d31fc
HW
487/*
488 * These are weird, but module loading must not be done with mutex
489 * held (since they will register), and we have to have a single
490 * function to use try_then_request_module().
491 */
492
493/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
494static inline struct ip6t_table *find_table_lock(const char *name)
1da177e4 495{
6b7d31fc 496 struct ip6t_table *t;
1da177e4 497
6b7d31fc
HW
498 if (down_interruptible(&ip6t_mutex) != 0)
499 return ERR_PTR(-EINTR);
1da177e4 500
6b7d31fc
HW
501 list_for_each_entry(t, &ip6t_tables, list)
502 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
503 return t;
504 up(&ip6t_mutex);
505 return NULL;
506}
1da177e4 507
6b7d31fc
HW
508/* Find match, grabs ref. Returns ERR_PTR() on error. */
509static inline struct ip6t_match *find_match(const char *name, u8 revision)
510{
511 struct ip6t_match *m;
512 int err = 0;
513
514 if (down_interruptible(&ip6t_mutex) != 0)
515 return ERR_PTR(-EINTR);
516
517 list_for_each_entry(m, &ip6t_match, list) {
518 if (strcmp(m->name, name) == 0) {
519 if (m->revision == revision) {
520 if (try_module_get(m->me)) {
521 up(&ip6t_mutex);
522 return m;
523 }
524 } else
525 err = -EPROTOTYPE; /* Found something. */
526 }
1da177e4 527 }
6b7d31fc
HW
528 up(&ip6t_mutex);
529 return ERR_PTR(err);
1da177e4
LT
530}
531
6b7d31fc
HW
532/* Find target, grabs ref. Returns ERR_PTR() on error. */
533static inline struct ip6t_target *find_target(const char *name, u8 revision)
1da177e4 534{
6b7d31fc
HW
535 struct ip6t_target *t;
536 int err = 0;
537
538 if (down_interruptible(&ip6t_mutex) != 0)
539 return ERR_PTR(-EINTR);
540
541 list_for_each_entry(t, &ip6t_target, list) {
542 if (strcmp(t->name, name) == 0) {
543 if (t->revision == revision) {
544 if (try_module_get(t->me)) {
545 up(&ip6t_mutex);
546 return t;
547 }
548 } else
549 err = -EPROTOTYPE; /* Found something. */
550 }
1da177e4 551 }
6b7d31fc
HW
552 up(&ip6t_mutex);
553 return ERR_PTR(err);
554}
1da177e4 555
6b7d31fc
HW
556struct ip6t_target *ip6t_find_target(const char *name, u8 revision)
557{
558 struct ip6t_target *target;
559
560 target = try_then_request_module(find_target(name, revision),
561 "ip6t_%s", name);
562 if (IS_ERR(target) || !target)
563 return NULL;
564 return target;
1da177e4 565}
1da177e4 566
6b7d31fc 567static int match_revfn(const char *name, u8 revision, int *bestp)
1da177e4 568{
6b7d31fc
HW
569 struct ip6t_match *m;
570 int have_rev = 0;
571
572 list_for_each_entry(m, &ip6t_match, list) {
573 if (strcmp(m->name, name) == 0) {
574 if (m->revision > *bestp)
575 *bestp = m->revision;
576 if (m->revision == revision)
577 have_rev = 1;
578 }
579 }
580 return have_rev;
1da177e4
LT
581}
582
6b7d31fc 583static int target_revfn(const char *name, u8 revision, int *bestp)
1da177e4 584{
6b7d31fc
HW
585 struct ip6t_target *t;
586 int have_rev = 0;
587
588 list_for_each_entry(t, &ip6t_target, list) {
589 if (strcmp(t->name, name) == 0) {
590 if (t->revision > *bestp)
591 *bestp = t->revision;
592 if (t->revision == revision)
593 have_rev = 1;
594 }
595 }
596 return have_rev;
1da177e4
LT
597}
598
6b7d31fc
HW
599/* Returns true or fals (if no such extension at all) */
600static inline int find_revision(const char *name, u8 revision,
601 int (*revfn)(const char *, u8, int *),
602 int *err)
1da177e4 603{
6b7d31fc
HW
604 int have_rev, best = -1;
605
606 if (down_interruptible(&ip6t_mutex) != 0) {
607 *err = -EINTR;
608 return 1;
609 }
610 have_rev = revfn(name, revision, &best);
611 up(&ip6t_mutex);
612
613 /* Nothing at all? Return 0 to try loading module. */
614 if (best == -1) {
615 *err = -ENOENT;
616 return 0;
617 }
618
619 *err = best;
620 if (!have_rev)
621 *err = -EPROTONOSUPPORT;
622 return 1;
1da177e4
LT
623}
624
6b7d31fc 625
1da177e4
LT
626/* All zeroes == unconditional rule. */
627static inline int
628unconditional(const struct ip6t_ip6 *ipv6)
629{
630 unsigned int i;
631
632 for (i = 0; i < sizeof(*ipv6); i++)
633 if (((char *)ipv6)[i])
634 break;
635
636 return (i == sizeof(*ipv6));
637}
638
639/* Figures out from what hook each rule can be called: returns 0 if
640 there are loops. Puts hook bitmask in comefrom. */
641static int
31836064
ED
642mark_source_chains(struct ip6t_table_info *newinfo,
643 unsigned int valid_hooks, void *entry0)
1da177e4
LT
644{
645 unsigned int hook;
646
647 /* No recursion; use packet counter to save back ptrs (reset
648 to 0 as we leave), and comefrom to save source hook bitmask */
649 for (hook = 0; hook < NF_IP6_NUMHOOKS; hook++) {
650 unsigned int pos = newinfo->hook_entry[hook];
651 struct ip6t_entry *e
31836064 652 = (struct ip6t_entry *)(entry0 + pos);
1da177e4
LT
653
654 if (!(valid_hooks & (1 << hook)))
655 continue;
656
657 /* Set initial back pointer. */
658 e->counters.pcnt = pos;
659
660 for (;;) {
661 struct ip6t_standard_target *t
662 = (void *)ip6t_get_target(e);
663
664 if (e->comefrom & (1 << NF_IP6_NUMHOOKS)) {
665 printk("iptables: loop hook %u pos %u %08X.\n",
666 hook, pos, e->comefrom);
667 return 0;
668 }
669 e->comefrom
670 |= ((1 << hook) | (1 << NF_IP6_NUMHOOKS));
671
672 /* Unconditional return/END. */
673 if (e->target_offset == sizeof(struct ip6t_entry)
674 && (strcmp(t->target.u.user.name,
675 IP6T_STANDARD_TARGET) == 0)
676 && t->verdict < 0
677 && unconditional(&e->ipv6)) {
678 unsigned int oldpos, size;
679
680 /* Return: backtrack through the last
681 big jump. */
682 do {
683 e->comefrom ^= (1<<NF_IP6_NUMHOOKS);
684#ifdef DEBUG_IP_FIREWALL_USER
685 if (e->comefrom
686 & (1 << NF_IP6_NUMHOOKS)) {
687 duprintf("Back unset "
688 "on hook %u "
689 "rule %u\n",
690 hook, pos);
691 }
692#endif
693 oldpos = pos;
694 pos = e->counters.pcnt;
695 e->counters.pcnt = 0;
696
697 /* We're at the start. */
698 if (pos == oldpos)
699 goto next;
700
701 e = (struct ip6t_entry *)
31836064 702 (entry0 + pos);
1da177e4
LT
703 } while (oldpos == pos + e->next_offset);
704
705 /* Move along one */
706 size = e->next_offset;
707 e = (struct ip6t_entry *)
31836064 708 (entry0 + pos + size);
1da177e4
LT
709 e->counters.pcnt = pos;
710 pos += size;
711 } else {
712 int newpos = t->verdict;
713
714 if (strcmp(t->target.u.user.name,
715 IP6T_STANDARD_TARGET) == 0
716 && newpos >= 0) {
717 /* This a jump; chase it. */
718 duprintf("Jump rule %u -> %u\n",
719 pos, newpos);
720 } else {
721 /* ... this is a fallthru */
722 newpos = pos + e->next_offset;
723 }
724 e = (struct ip6t_entry *)
31836064 725 (entry0 + newpos);
1da177e4
LT
726 e->counters.pcnt = pos;
727 pos = newpos;
728 }
729 }
730 next:
731 duprintf("Finished chain %u\n", hook);
732 }
733 return 1;
734}
735
736static inline int
737cleanup_match(struct ip6t_entry_match *m, unsigned int *i)
738{
739 if (i && (*i)-- == 0)
740 return 1;
741
742 if (m->u.kernel.match->destroy)
743 m->u.kernel.match->destroy(m->data,
744 m->u.match_size - sizeof(*m));
745 module_put(m->u.kernel.match->me);
746 return 0;
747}
748
749static inline int
750standard_check(const struct ip6t_entry_target *t,
751 unsigned int max_offset)
752{
753 struct ip6t_standard_target *targ = (void *)t;
754
755 /* Check standard info. */
756 if (t->u.target_size
757 != IP6T_ALIGN(sizeof(struct ip6t_standard_target))) {
758 duprintf("standard_check: target size %u != %u\n",
759 t->u.target_size,
760 IP6T_ALIGN(sizeof(struct ip6t_standard_target)));
761 return 0;
762 }
763
764 if (targ->verdict >= 0
765 && targ->verdict > max_offset - sizeof(struct ip6t_entry)) {
766 duprintf("ip6t_standard_check: bad verdict (%i)\n",
767 targ->verdict);
768 return 0;
769 }
770
771 if (targ->verdict < -NF_MAX_VERDICT - 1) {
772 duprintf("ip6t_standard_check: bad negative verdict (%i)\n",
773 targ->verdict);
774 return 0;
775 }
776 return 1;
777}
778
779static inline int
780check_match(struct ip6t_entry_match *m,
781 const char *name,
782 const struct ip6t_ip6 *ipv6,
783 unsigned int hookmask,
784 unsigned int *i)
785{
1da177e4
LT
786 struct ip6t_match *match;
787
6b7d31fc
HW
788 match = try_then_request_module(find_match(m->u.user.name,
789 m->u.user.revision),
790 "ip6t_%s", m->u.user.name);
791 if (IS_ERR(match) || !match) {
792 duprintf("check_match: `%s' not found\n", m->u.user.name);
793 return match ? PTR_ERR(match) : -ENOENT;
1da177e4
LT
794 }
795 m->u.kernel.match = match;
1da177e4
LT
796
797 if (m->u.kernel.match->checkentry
798 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
799 m->u.match_size - sizeof(*m),
800 hookmask)) {
801 module_put(m->u.kernel.match->me);
802 duprintf("ip_tables: check failed for `%s'.\n",
803 m->u.kernel.match->name);
804 return -EINVAL;
805 }
806
807 (*i)++;
808 return 0;
809}
810
811static struct ip6t_target ip6t_standard_target;
812
813static inline int
814check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
815 unsigned int *i)
816{
817 struct ip6t_entry_target *t;
818 struct ip6t_target *target;
819 int ret;
820 unsigned int j;
821
822 if (!ip6_checkentry(&e->ipv6)) {
823 duprintf("ip_tables: ip check failed %p %s.\n", e, name);
824 return -EINVAL;
825 }
826
827 j = 0;
828 ret = IP6T_MATCH_ITERATE(e, check_match, name, &e->ipv6, e->comefrom, &j);
829 if (ret != 0)
830 goto cleanup_matches;
831
832 t = ip6t_get_target(e);
6b7d31fc
HW
833 target = try_then_request_module(find_target(t->u.user.name,
834 t->u.user.revision),
835 "ip6t_%s", t->u.user.name);
836 if (IS_ERR(target) || !target) {
1da177e4 837 duprintf("check_entry: `%s' not found\n", t->u.user.name);
6b7d31fc 838 ret = target ? PTR_ERR(target) : -ENOENT;
1da177e4
LT
839 goto cleanup_matches;
840 }
841 t->u.kernel.target = target;
6b7d31fc 842
1da177e4
LT
843 if (t->u.kernel.target == &ip6t_standard_target) {
844 if (!standard_check(t, size)) {
845 ret = -EINVAL;
846 goto cleanup_matches;
847 }
848 } else if (t->u.kernel.target->checkentry
849 && !t->u.kernel.target->checkentry(name, e, t->data,
850 t->u.target_size
851 - sizeof(*t),
852 e->comefrom)) {
853 module_put(t->u.kernel.target->me);
854 duprintf("ip_tables: check failed for `%s'.\n",
855 t->u.kernel.target->name);
856 ret = -EINVAL;
857 goto cleanup_matches;
858 }
859
860 (*i)++;
861 return 0;
862
863 cleanup_matches:
864 IP6T_MATCH_ITERATE(e, cleanup_match, &j);
865 return ret;
866}
867
868static inline int
869check_entry_size_and_hooks(struct ip6t_entry *e,
870 struct ip6t_table_info *newinfo,
871 unsigned char *base,
872 unsigned char *limit,
873 const unsigned int *hook_entries,
874 const unsigned int *underflows,
875 unsigned int *i)
876{
877 unsigned int h;
878
879 if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0
880 || (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) {
881 duprintf("Bad offset %p\n", e);
882 return -EINVAL;
883 }
884
885 if (e->next_offset
886 < sizeof(struct ip6t_entry) + sizeof(struct ip6t_entry_target)) {
887 duprintf("checking: element %p size %u\n",
888 e, e->next_offset);
889 return -EINVAL;
890 }
891
892 /* Check hooks & underflows */
893 for (h = 0; h < NF_IP6_NUMHOOKS; h++) {
894 if ((unsigned char *)e - base == hook_entries[h])
895 newinfo->hook_entry[h] = hook_entries[h];
896 if ((unsigned char *)e - base == underflows[h])
897 newinfo->underflow[h] = underflows[h];
898 }
899
900 /* FIXME: underflows must be unconditional, standard verdicts
901 < 0 (not IP6T_RETURN). --RR */
902
903 /* Clear counters and comefrom */
904 e->counters = ((struct ip6t_counters) { 0, 0 });
905 e->comefrom = 0;
906
907 (*i)++;
908 return 0;
909}
910
911static inline int
912cleanup_entry(struct ip6t_entry *e, unsigned int *i)
913{
914 struct ip6t_entry_target *t;
915
916 if (i && (*i)-- == 0)
917 return 1;
918
919 /* Cleanup all matches */
920 IP6T_MATCH_ITERATE(e, cleanup_match, NULL);
921 t = ip6t_get_target(e);
922 if (t->u.kernel.target->destroy)
923 t->u.kernel.target->destroy(t->data,
924 t->u.target_size - sizeof(*t));
925 module_put(t->u.kernel.target->me);
926 return 0;
927}
928
929/* Checks and translates the user-supplied table segment (held in
930 newinfo) */
931static int
932translate_table(const char *name,
933 unsigned int valid_hooks,
934 struct ip6t_table_info *newinfo,
31836064 935 void *entry0,
1da177e4
LT
936 unsigned int size,
937 unsigned int number,
938 const unsigned int *hook_entries,
939 const unsigned int *underflows)
940{
941 unsigned int i;
942 int ret;
943
944 newinfo->size = size;
945 newinfo->number = number;
946
947 /* Init all hooks to impossible value. */
948 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
949 newinfo->hook_entry[i] = 0xFFFFFFFF;
950 newinfo->underflow[i] = 0xFFFFFFFF;
951 }
952
953 duprintf("translate_table: size %u\n", newinfo->size);
954 i = 0;
955 /* Walk through entries, checking offsets. */
31836064 956 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
1da177e4
LT
957 check_entry_size_and_hooks,
958 newinfo,
31836064
ED
959 entry0,
960 entry0 + size,
1da177e4
LT
961 hook_entries, underflows, &i);
962 if (ret != 0)
963 return ret;
964
965 if (i != number) {
966 duprintf("translate_table: %u not %u entries\n",
967 i, number);
968 return -EINVAL;
969 }
970
971 /* Check hooks all assigned */
972 for (i = 0; i < NF_IP6_NUMHOOKS; i++) {
973 /* Only hooks which are valid */
974 if (!(valid_hooks & (1 << i)))
975 continue;
976 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
977 duprintf("Invalid hook entry %u %u\n",
978 i, hook_entries[i]);
979 return -EINVAL;
980 }
981 if (newinfo->underflow[i] == 0xFFFFFFFF) {
982 duprintf("Invalid underflow %u %u\n",
983 i, underflows[i]);
984 return -EINVAL;
985 }
986 }
987
31836064 988 if (!mark_source_chains(newinfo, valid_hooks, entry0))
1da177e4
LT
989 return -ELOOP;
990
991 /* Finally, each sanity check must pass */
992 i = 0;
31836064 993 ret = IP6T_ENTRY_ITERATE(entry0, newinfo->size,
1da177e4
LT
994 check_entry, name, size, &i);
995
996 if (ret != 0) {
31836064 997 IP6T_ENTRY_ITERATE(entry0, newinfo->size,
1da177e4
LT
998 cleanup_entry, &i);
999 return ret;
1000 }
1001
1002 /* And one copy for every other CPU */
c8923c6b 1003 for_each_cpu(i) {
31836064
ED
1004 if (newinfo->entries[i] && newinfo->entries[i] != entry0)
1005 memcpy(newinfo->entries[i], entry0, newinfo->size);
1da177e4
LT
1006 }
1007
1008 return ret;
1009}
1010
1011static struct ip6t_table_info *
1012replace_table(struct ip6t_table *table,
1013 unsigned int num_counters,
1014 struct ip6t_table_info *newinfo,
1015 int *error)
1016{
1017 struct ip6t_table_info *oldinfo;
1018
1019#ifdef CONFIG_NETFILTER_DEBUG
1020 {
31836064 1021 int cpu;
1da177e4 1022
31836064
ED
1023 for_each_cpu(cpu) {
1024 struct ip6t_entry *table_base = newinfo->entries[cpu];
1025 if (table_base)
1026 table_base->comefrom = 0xdead57ac;
1da177e4
LT
1027 }
1028 }
1029#endif
1030
1031 /* Do the substitution. */
1032 write_lock_bh(&table->lock);
1033 /* Check inside lock: is the old number correct? */
1034 if (num_counters != table->private->number) {
1035 duprintf("num_counters != table->private->number (%u/%u)\n",
1036 num_counters, table->private->number);
1037 write_unlock_bh(&table->lock);
1038 *error = -EAGAIN;
1039 return NULL;
1040 }
1041 oldinfo = table->private;
1042 table->private = newinfo;
1043 newinfo->initial_entries = oldinfo->initial_entries;
1044 write_unlock_bh(&table->lock);
1045
1046 return oldinfo;
1047}
1048
1049/* Gets counters. */
1050static inline int
1051add_entry_to_counter(const struct ip6t_entry *e,
1052 struct ip6t_counters total[],
1053 unsigned int *i)
1054{
1055 ADD_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1056
1057 (*i)++;
1058 return 0;
1059}
1060
31836064
ED
1061static inline int
1062set_entry_to_counter(const struct ip6t_entry *e,
1063 struct ip6t_counters total[],
1064 unsigned int *i)
1065{
1066 SET_COUNTER(total[*i], e->counters.bcnt, e->counters.pcnt);
1067
1068 (*i)++;
1069 return 0;
1070}
1071
1da177e4
LT
1072static void
1073get_counters(const struct ip6t_table_info *t,
1074 struct ip6t_counters counters[])
1075{
1076 unsigned int cpu;
1077 unsigned int i;
31836064
ED
1078 unsigned int curcpu;
1079
1080 /* Instead of clearing (by a previous call to memset())
1081 * the counters and using adds, we set the counters
1082 * with data used by 'current' CPU
1083 * We dont care about preemption here.
1084 */
1085 curcpu = raw_smp_processor_id();
1086
1087 i = 0;
1088 IP6T_ENTRY_ITERATE(t->entries[curcpu],
1089 t->size,
1090 set_entry_to_counter,
1091 counters,
1092 &i);
1da177e4 1093
c8923c6b 1094 for_each_cpu(cpu) {
31836064
ED
1095 if (cpu == curcpu)
1096 continue;
1da177e4 1097 i = 0;
31836064 1098 IP6T_ENTRY_ITERATE(t->entries[cpu],
1da177e4
LT
1099 t->size,
1100 add_entry_to_counter,
1101 counters,
1102 &i);
1103 }
1104}
1105
1106static int
1107copy_entries_to_user(unsigned int total_size,
1108 struct ip6t_table *table,
1109 void __user *userptr)
1110{
1111 unsigned int off, num, countersize;
1112 struct ip6t_entry *e;
1113 struct ip6t_counters *counters;
1114 int ret = 0;
31836064 1115 void *loc_cpu_entry;
1da177e4
LT
1116
1117 /* We need atomic snapshot of counters: rest doesn't change
1118 (other than comefrom, which userspace doesn't care
1119 about). */
1120 countersize = sizeof(struct ip6t_counters) * table->private->number;
1121 counters = vmalloc(countersize);
1122
1123 if (counters == NULL)
1124 return -ENOMEM;
1125
1126 /* First, sum counters... */
1da177e4
LT
1127 write_lock_bh(&table->lock);
1128 get_counters(table->private, counters);
1129 write_unlock_bh(&table->lock);
1130
31836064
ED
1131 /* choose the copy that is on ourc node/cpu */
1132 loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
1133 if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
1da177e4
LT
1134 ret = -EFAULT;
1135 goto free_counters;
1136 }
1137
1138 /* FIXME: use iterator macros --RR */
1139 /* ... then go back and fix counters and names */
1140 for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
1141 unsigned int i;
1142 struct ip6t_entry_match *m;
1143 struct ip6t_entry_target *t;
1144
31836064 1145 e = (struct ip6t_entry *)(loc_cpu_entry + off);
1da177e4
LT
1146 if (copy_to_user(userptr + off
1147 + offsetof(struct ip6t_entry, counters),
1148 &counters[num],
1149 sizeof(counters[num])) != 0) {
1150 ret = -EFAULT;
1151 goto free_counters;
1152 }
1153
1154 for (i = sizeof(struct ip6t_entry);
1155 i < e->target_offset;
1156 i += m->u.match_size) {
1157 m = (void *)e + i;
1158
1159 if (copy_to_user(userptr + off + i
1160 + offsetof(struct ip6t_entry_match,
1161 u.user.name),
1162 m->u.kernel.match->name,
1163 strlen(m->u.kernel.match->name)+1)
1164 != 0) {
1165 ret = -EFAULT;
1166 goto free_counters;
1167 }
1168 }
1169
1170 t = ip6t_get_target(e);
1171 if (copy_to_user(userptr + off + e->target_offset
1172 + offsetof(struct ip6t_entry_target,
1173 u.user.name),
1174 t->u.kernel.target->name,
1175 strlen(t->u.kernel.target->name)+1) != 0) {
1176 ret = -EFAULT;
1177 goto free_counters;
1178 }
1179 }
1180
1181 free_counters:
1182 vfree(counters);
1183 return ret;
1184}
1185
1186static int
1187get_entries(const struct ip6t_get_entries *entries,
1188 struct ip6t_get_entries __user *uptr)
1189{
1190 int ret;
1191 struct ip6t_table *t;
1192
6b7d31fc
HW
1193 t = find_table_lock(entries->name);
1194 if (t && !IS_ERR(t)) {
1da177e4
LT
1195 duprintf("t->private->number = %u\n",
1196 t->private->number);
1197 if (entries->size == t->private->size)
1198 ret = copy_entries_to_user(t->private->size,
1199 t, uptr->entrytable);
1200 else {
1201 duprintf("get_entries: I've got %u not %u!\n",
1202 t->private->size,
1203 entries->size);
1204 ret = -EINVAL;
1205 }
6b7d31fc 1206 module_put(t->me);
1da177e4
LT
1207 up(&ip6t_mutex);
1208 } else
6b7d31fc 1209 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4
LT
1210
1211 return ret;
1212}
1213
31836064
ED
1214static void free_table_info(struct ip6t_table_info *info)
1215{
1216 int cpu;
1217 for_each_cpu(cpu) {
1218 if (info->size <= PAGE_SIZE)
1219 kfree(info->entries[cpu]);
1220 else
1221 vfree(info->entries[cpu]);
1222 }
1223 kfree(info);
1224}
1225
1226static struct ip6t_table_info *alloc_table_info(unsigned int size)
1227{
1228 struct ip6t_table_info *newinfo;
1229 int cpu;
1230
1231 newinfo = kzalloc(sizeof(struct ip6t_table_info), GFP_KERNEL);
1232 if (!newinfo)
1233 return NULL;
1234
1235 newinfo->size = size;
1236
1237 for_each_cpu(cpu) {
1238 if (size <= PAGE_SIZE)
1239 newinfo->entries[cpu] = kmalloc_node(size,
1240 GFP_KERNEL,
1241 cpu_to_node(cpu));
1242 else
1243 newinfo->entries[cpu] = vmalloc_node(size,
1244 cpu_to_node(cpu));
1245 if (newinfo->entries[cpu] == NULL) {
1246 free_table_info(newinfo);
1247 return NULL;
1248 }
1249 }
1250
1251 return newinfo;
1252}
1253
1da177e4
LT
1254static int
1255do_replace(void __user *user, unsigned int len)
1256{
1257 int ret;
1258 struct ip6t_replace tmp;
1259 struct ip6t_table *t;
1260 struct ip6t_table_info *newinfo, *oldinfo;
1261 struct ip6t_counters *counters;
31836064 1262 void *loc_cpu_entry, *loc_cpu_old_entry;
1da177e4
LT
1263
1264 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1265 return -EFAULT;
1266
1267 /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */
1268 if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages)
1269 return -ENOMEM;
1270
31836064 1271 newinfo = alloc_table_info(tmp.size);
1da177e4
LT
1272 if (!newinfo)
1273 return -ENOMEM;
1274
31836064
ED
1275 /* choose the copy that is on our node/cpu */
1276 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1277 if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1da177e4
LT
1278 tmp.size) != 0) {
1279 ret = -EFAULT;
1280 goto free_newinfo;
1281 }
1282
1283 counters = vmalloc(tmp.num_counters * sizeof(struct ip6t_counters));
1284 if (!counters) {
1285 ret = -ENOMEM;
1286 goto free_newinfo;
1287 }
1da177e4
LT
1288
1289 ret = translate_table(tmp.name, tmp.valid_hooks,
31836064 1290 newinfo, loc_cpu_entry, tmp.size, tmp.num_entries,
1da177e4
LT
1291 tmp.hook_entry, tmp.underflow);
1292 if (ret != 0)
1293 goto free_newinfo_counters;
1294
1295 duprintf("ip_tables: Translated table\n");
1296
6b7d31fc
HW
1297 t = try_then_request_module(find_table_lock(tmp.name),
1298 "ip6table_%s", tmp.name);
1299 if (!t || IS_ERR(t)) {
1300 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4 1301 goto free_newinfo_counters_untrans;
6b7d31fc 1302 }
1da177e4
LT
1303
1304 /* You lied! */
1305 if (tmp.valid_hooks != t->valid_hooks) {
1306 duprintf("Valid hook crap: %08X vs %08X\n",
1307 tmp.valid_hooks, t->valid_hooks);
1308 ret = -EINVAL;
6b7d31fc 1309 goto put_module;
1da177e4
LT
1310 }
1311
1312 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
1313 if (!oldinfo)
1314 goto put_module;
1315
1316 /* Update module usage count based on number of rules */
1317 duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1318 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1319 if ((oldinfo->number > oldinfo->initial_entries) ||
1320 (newinfo->number <= oldinfo->initial_entries))
1321 module_put(t->me);
1322 if ((oldinfo->number > oldinfo->initial_entries) &&
1323 (newinfo->number <= oldinfo->initial_entries))
1324 module_put(t->me);
1325
1326 /* Get the old counters. */
1327 get_counters(oldinfo, counters);
1328 /* Decrease module usage counts and free resource */
31836064
ED
1329 loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
1330 IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,NULL);
1331 free_table_info(oldinfo);
1da177e4
LT
1332 if (copy_to_user(tmp.counters, counters,
1333 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1334 ret = -EFAULT;
1335 vfree(counters);
1336 up(&ip6t_mutex);
1337 return ret;
1338
1339 put_module:
1340 module_put(t->me);
1da177e4
LT
1341 up(&ip6t_mutex);
1342 free_newinfo_counters_untrans:
31836064 1343 IP6T_ENTRY_ITERATE(loc_cpu_entry, newinfo->size, cleanup_entry,NULL);
1da177e4
LT
1344 free_newinfo_counters:
1345 vfree(counters);
1346 free_newinfo:
31836064 1347 free_table_info(newinfo);
1da177e4
LT
1348 return ret;
1349}
1350
1351/* We're lazy, and add to the first CPU; overflow works its fey magic
1352 * and everything is OK. */
1353static inline int
1354add_counter_to_entry(struct ip6t_entry *e,
1355 const struct ip6t_counters addme[],
1356 unsigned int *i)
1357{
1358#if 0
1359 duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n",
1360 *i,
1361 (long unsigned int)e->counters.pcnt,
1362 (long unsigned int)e->counters.bcnt,
1363 (long unsigned int)addme[*i].pcnt,
1364 (long unsigned int)addme[*i].bcnt);
1365#endif
1366
1367 ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
1368
1369 (*i)++;
1370 return 0;
1371}
1372
1373static int
1374do_add_counters(void __user *user, unsigned int len)
1375{
1376 unsigned int i;
1377 struct ip6t_counters_info tmp, *paddc;
1378 struct ip6t_table *t;
6b7d31fc 1379 int ret = 0;
31836064 1380 void *loc_cpu_entry;
1da177e4
LT
1381
1382 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1383 return -EFAULT;
1384
1385 if (len != sizeof(tmp) + tmp.num_counters*sizeof(struct ip6t_counters))
1386 return -EINVAL;
1387
1388 paddc = vmalloc(len);
1389 if (!paddc)
1390 return -ENOMEM;
1391
1392 if (copy_from_user(paddc, user, len) != 0) {
1393 ret = -EFAULT;
1394 goto free;
1395 }
1396
6b7d31fc
HW
1397 t = find_table_lock(tmp.name);
1398 if (!t || IS_ERR(t)) {
1399 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4 1400 goto free;
6b7d31fc 1401 }
1da177e4
LT
1402
1403 write_lock_bh(&t->lock);
1404 if (t->private->number != paddc->num_counters) {
1405 ret = -EINVAL;
1406 goto unlock_up_free;
1407 }
1408
1409 i = 0;
31836064
ED
1410 /* Choose the copy that is on our node */
1411 loc_cpu_entry = t->private->entries[smp_processor_id()];
1412 IP6T_ENTRY_ITERATE(loc_cpu_entry,
1da177e4
LT
1413 t->private->size,
1414 add_counter_to_entry,
1415 paddc->counters,
1416 &i);
1417 unlock_up_free:
1418 write_unlock_bh(&t->lock);
1419 up(&ip6t_mutex);
6b7d31fc 1420 module_put(t->me);
1da177e4
LT
1421 free:
1422 vfree(paddc);
1423
1424 return ret;
1425}
1426
1427static int
1428do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1429{
1430 int ret;
1431
1432 if (!capable(CAP_NET_ADMIN))
1433 return -EPERM;
1434
1435 switch (cmd) {
1436 case IP6T_SO_SET_REPLACE:
1437 ret = do_replace(user, len);
1438 break;
1439
1440 case IP6T_SO_SET_ADD_COUNTERS:
1441 ret = do_add_counters(user, len);
1442 break;
1443
1444 default:
1445 duprintf("do_ip6t_set_ctl: unknown request %i\n", cmd);
1446 ret = -EINVAL;
1447 }
1448
1449 return ret;
1450}
1451
1452static int
1453do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1454{
1455 int ret;
1456
1457 if (!capable(CAP_NET_ADMIN))
1458 return -EPERM;
1459
1460 switch (cmd) {
1461 case IP6T_SO_GET_INFO: {
1462 char name[IP6T_TABLE_MAXNAMELEN];
1463 struct ip6t_table *t;
1464
1465 if (*len != sizeof(struct ip6t_getinfo)) {
1466 duprintf("length %u != %u\n", *len,
1467 sizeof(struct ip6t_getinfo));
1468 ret = -EINVAL;
1469 break;
1470 }
1471
1472 if (copy_from_user(name, user, sizeof(name)) != 0) {
1473 ret = -EFAULT;
1474 break;
1475 }
1476 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
6b7d31fc
HW
1477
1478 t = try_then_request_module(find_table_lock(name),
1479 "ip6table_%s", name);
1480 if (t && !IS_ERR(t)) {
1da177e4
LT
1481 struct ip6t_getinfo info;
1482
1483 info.valid_hooks = t->valid_hooks;
1484 memcpy(info.hook_entry, t->private->hook_entry,
1485 sizeof(info.hook_entry));
1486 memcpy(info.underflow, t->private->underflow,
1487 sizeof(info.underflow));
1488 info.num_entries = t->private->number;
1489 info.size = t->private->size;
1490 memcpy(info.name, name, sizeof(info.name));
1491
1492 if (copy_to_user(user, &info, *len) != 0)
1493 ret = -EFAULT;
1494 else
1495 ret = 0;
1da177e4 1496 up(&ip6t_mutex);
6b7d31fc
HW
1497 module_put(t->me);
1498 } else
1499 ret = t ? PTR_ERR(t) : -ENOENT;
1da177e4
LT
1500 }
1501 break;
1502
1503 case IP6T_SO_GET_ENTRIES: {
1504 struct ip6t_get_entries get;
1505
1506 if (*len < sizeof(get)) {
1507 duprintf("get_entries: %u < %u\n", *len, sizeof(get));
1508 ret = -EINVAL;
1509 } else if (copy_from_user(&get, user, sizeof(get)) != 0) {
1510 ret = -EFAULT;
1511 } else if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1512 duprintf("get_entries: %u != %u\n", *len,
1513 sizeof(struct ip6t_get_entries) + get.size);
1514 ret = -EINVAL;
1515 } else
1516 ret = get_entries(&get, user);
1517 break;
1518 }
1519
6b7d31fc
HW
1520 case IP6T_SO_GET_REVISION_MATCH:
1521 case IP6T_SO_GET_REVISION_TARGET: {
1522 struct ip6t_get_revision rev;
1523 int (*revfn)(const char *, u8, int *);
1524
1525 if (*len != sizeof(rev)) {
1526 ret = -EINVAL;
1527 break;
1528 }
1529 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1530 ret = -EFAULT;
1531 break;
1532 }
1533
1534 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1535 revfn = target_revfn;
1536 else
1537 revfn = match_revfn;
1538
1539 try_then_request_module(find_revision(rev.name, rev.revision,
1540 revfn, &ret),
1541 "ip6t_%s", rev.name);
1542 break;
1543 }
1544
1da177e4
LT
1545 default:
1546 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1547 ret = -EINVAL;
1548 }
1549
1550 return ret;
1551}
1552
1553/* Registration hooks for targets. */
1554int
1555ip6t_register_target(struct ip6t_target *target)
1556{
1557 int ret;
1558
1559 ret = down_interruptible(&ip6t_mutex);
1560 if (ret != 0)
1561 return ret;
6b7d31fc 1562 list_add(&target->list, &ip6t_target);
1da177e4
LT
1563 up(&ip6t_mutex);
1564 return ret;
1565}
1566
1567void
1568ip6t_unregister_target(struct ip6t_target *target)
1569{
1570 down(&ip6t_mutex);
1571 LIST_DELETE(&ip6t_target, target);
1572 up(&ip6t_mutex);
1573}
1574
1575int
1576ip6t_register_match(struct ip6t_match *match)
1577{
1578 int ret;
1579
1580 ret = down_interruptible(&ip6t_mutex);
1581 if (ret != 0)
1582 return ret;
1583
6b7d31fc 1584 list_add(&match->list, &ip6t_match);
1da177e4
LT
1585 up(&ip6t_mutex);
1586
1587 return ret;
1588}
1589
1590void
1591ip6t_unregister_match(struct ip6t_match *match)
1592{
1593 down(&ip6t_mutex);
1594 LIST_DELETE(&ip6t_match, match);
1595 up(&ip6t_mutex);
1596}
1597
1598int ip6t_register_table(struct ip6t_table *table,
1599 const struct ip6t_replace *repl)
1600{
1601 int ret;
1602 struct ip6t_table_info *newinfo;
1603 static struct ip6t_table_info bootstrap
1604 = { 0, 0, 0, { 0 }, { 0 }, { } };
31836064 1605 void *loc_cpu_entry;
1da177e4 1606
31836064 1607 newinfo = alloc_table_info(repl->size);
1da177e4
LT
1608 if (!newinfo)
1609 return -ENOMEM;
1610
31836064
ED
1611 /* choose the copy on our node/cpu */
1612 loc_cpu_entry = newinfo->entries[raw_smp_processor_id()];
1613 memcpy(loc_cpu_entry, repl->entries, repl->size);
1da177e4
LT
1614
1615 ret = translate_table(table->name, table->valid_hooks,
31836064 1616 newinfo, loc_cpu_entry, repl->size,
1da177e4
LT
1617 repl->num_entries,
1618 repl->hook_entry,
1619 repl->underflow);
1620 if (ret != 0) {
31836064 1621 free_table_info(newinfo);
1da177e4
LT
1622 return ret;
1623 }
1624
1625 ret = down_interruptible(&ip6t_mutex);
1626 if (ret != 0) {
31836064 1627 free_table_info(newinfo);
1da177e4
LT
1628 return ret;
1629 }
1630
1631 /* Don't autoload: we'd eat our tail... */
1632 if (list_named_find(&ip6t_tables, table->name)) {
1633 ret = -EEXIST;
1634 goto free_unlock;
1635 }
1636
1637 /* Simplifies replace_table code. */
1638 table->private = &bootstrap;
1639 if (!replace_table(table, 0, newinfo, &ret))
1640 goto free_unlock;
1641
1642 duprintf("table->private->number = %u\n",
1643 table->private->number);
1644
1645 /* save number of initial entries */
1646 table->private->initial_entries = table->private->number;
1647
1648 rwlock_init(&table->lock);
1649 list_prepend(&ip6t_tables, table);
1650
1651 unlock:
1652 up(&ip6t_mutex);
1653 return ret;
1654
1655 free_unlock:
31836064 1656 free_table_info(newinfo);
1da177e4
LT
1657 goto unlock;
1658}
1659
1660void ip6t_unregister_table(struct ip6t_table *table)
1661{
31836064
ED
1662 void *loc_cpu_entry;
1663
1da177e4
LT
1664 down(&ip6t_mutex);
1665 LIST_DELETE(&ip6t_tables, table);
1666 up(&ip6t_mutex);
1667
1668 /* Decrease module usage counts and free resources */
31836064
ED
1669 loc_cpu_entry = table->private->entries[raw_smp_processor_id()];
1670 IP6T_ENTRY_ITERATE(loc_cpu_entry, table->private->size,
1da177e4 1671 cleanup_entry, NULL);
31836064 1672 free_table_info(table->private);
1da177e4
LT
1673}
1674
1675/* Returns 1 if the port is matched by the range, 0 otherwise */
1676static inline int
1677port_match(u_int16_t min, u_int16_t max, u_int16_t port, int invert)
1678{
1679 int ret;
1680
1681 ret = (port >= min && port <= max) ^ invert;
1682 return ret;
1683}
1684
1685static int
1686tcp_find_option(u_int8_t option,
1687 const struct sk_buff *skb,
1688 unsigned int tcpoff,
1689 unsigned int optlen,
1690 int invert,
1691 int *hotdrop)
1692{
1693 /* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
1694 u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
1695 unsigned int i;
1696
1697 duprintf("tcp_match: finding option\n");
1698 if (!optlen)
1699 return invert;
1700 /* If we don't have the whole header, drop packet. */
1701 op = skb_header_pointer(skb, tcpoff + sizeof(struct tcphdr), optlen,
1702 _opt);
1703 if (op == NULL) {
1704 *hotdrop = 1;
1705 return 0;
1706 }
1707
1708 for (i = 0; i < optlen; ) {
1709 if (op[i] == option) return !invert;
1710 if (op[i] < 2) i++;
1711 else i += op[i+1]?:1;
1712 }
1713
1714 return invert;
1715}
1716
1717static int
1718tcp_match(const struct sk_buff *skb,
1719 const struct net_device *in,
1720 const struct net_device *out,
1721 const void *matchinfo,
1722 int offset,
1723 unsigned int protoff,
1724 int *hotdrop)
1725{
1726 struct tcphdr _tcph, *th;
1727 const struct ip6t_tcp *tcpinfo = matchinfo;
1728
1729 if (offset) {
1730 /* To quote Alan:
1731
1732 Don't allow a fragment of TCP 8 bytes in. Nobody normal
1733 causes this. Its a cracker trying to break in by doing a
1734 flag overwrite to pass the direction checks.
1735 */
1736 if (offset == 1) {
1737 duprintf("Dropping evil TCP offset=1 frag.\n");
1738 *hotdrop = 1;
1739 }
1740 /* Must not be a fragment. */
1741 return 0;
1742 }
1743
1744#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
1745
1746 th = skb_header_pointer(skb, protoff, sizeof(_tcph), &_tcph);
1747 if (th == NULL) {
1748 /* We've been asked to examine this packet, and we
1749 can't. Hence, no choice but to drop. */
1750 duprintf("Dropping evil TCP offset=0 tinygram.\n");
1751 *hotdrop = 1;
1752 return 0;
1753 }
1754
1755 if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
1756 ntohs(th->source),
1757 !!(tcpinfo->invflags & IP6T_TCP_INV_SRCPT)))
1758 return 0;
1759 if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
1760 ntohs(th->dest),
1761 !!(tcpinfo->invflags & IP6T_TCP_INV_DSTPT)))
1762 return 0;
1763 if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
1764 == tcpinfo->flg_cmp,
1765 IP6T_TCP_INV_FLAGS))
1766 return 0;
1767 if (tcpinfo->option) {
1768 if (th->doff * 4 < sizeof(_tcph)) {
1769 *hotdrop = 1;
1770 return 0;
1771 }
1772 if (!tcp_find_option(tcpinfo->option, skb, protoff,
1773 th->doff*4 - sizeof(*th),
1774 tcpinfo->invflags & IP6T_TCP_INV_OPTION,
1775 hotdrop))
1776 return 0;
1777 }
1778 return 1;
1779}
1780
1781/* Called when user tries to insert an entry of this type. */
1782static int
1783tcp_checkentry(const char *tablename,
1784 const struct ip6t_ip6 *ipv6,
1785 void *matchinfo,
1786 unsigned int matchsize,
1787 unsigned int hook_mask)
1788{
1789 const struct ip6t_tcp *tcpinfo = matchinfo;
1790
1791 /* Must specify proto == TCP, and no unknown invflags */
1792 return ipv6->proto == IPPROTO_TCP
1793 && !(ipv6->invflags & IP6T_INV_PROTO)
1794 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_tcp))
1795 && !(tcpinfo->invflags & ~IP6T_TCP_INV_MASK);
1796}
1797
1798static int
1799udp_match(const struct sk_buff *skb,
1800 const struct net_device *in,
1801 const struct net_device *out,
1802 const void *matchinfo,
1803 int offset,
1804 unsigned int protoff,
1805 int *hotdrop)
1806{
1807 struct udphdr _udph, *uh;
1808 const struct ip6t_udp *udpinfo = matchinfo;
1809
1810 /* Must not be a fragment. */
1811 if (offset)
1812 return 0;
1813
1814 uh = skb_header_pointer(skb, protoff, sizeof(_udph), &_udph);
1815 if (uh == NULL) {
1816 /* We've been asked to examine this packet, and we
1817 can't. Hence, no choice but to drop. */
1818 duprintf("Dropping evil UDP tinygram.\n");
1819 *hotdrop = 1;
1820 return 0;
1821 }
1822
1823 return port_match(udpinfo->spts[0], udpinfo->spts[1],
1824 ntohs(uh->source),
1825 !!(udpinfo->invflags & IP6T_UDP_INV_SRCPT))
1826 && port_match(udpinfo->dpts[0], udpinfo->dpts[1],
1827 ntohs(uh->dest),
1828 !!(udpinfo->invflags & IP6T_UDP_INV_DSTPT));
1829}
1830
1831/* Called when user tries to insert an entry of this type. */
1832static int
1833udp_checkentry(const char *tablename,
1834 const struct ip6t_ip6 *ipv6,
1835 void *matchinfo,
1836 unsigned int matchinfosize,
1837 unsigned int hook_mask)
1838{
1839 const struct ip6t_udp *udpinfo = matchinfo;
1840
1841 /* Must specify proto == UDP, and no unknown invflags */
1842 if (ipv6->proto != IPPROTO_UDP || (ipv6->invflags & IP6T_INV_PROTO)) {
1843 duprintf("ip6t_udp: Protocol %u != %u\n", ipv6->proto,
1844 IPPROTO_UDP);
1845 return 0;
1846 }
1847 if (matchinfosize != IP6T_ALIGN(sizeof(struct ip6t_udp))) {
1848 duprintf("ip6t_udp: matchsize %u != %u\n",
1849 matchinfosize, IP6T_ALIGN(sizeof(struct ip6t_udp)));
1850 return 0;
1851 }
1852 if (udpinfo->invflags & ~IP6T_UDP_INV_MASK) {
1853 duprintf("ip6t_udp: unknown flags %X\n",
1854 udpinfo->invflags);
1855 return 0;
1856 }
1857
1858 return 1;
1859}
1860
1861/* Returns 1 if the type and code is matched by the range, 0 otherwise */
1862static inline int
1863icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1864 u_int8_t type, u_int8_t code,
1865 int invert)
1866{
1867 return (type == test_type && code >= min_code && code <= max_code)
1868 ^ invert;
1869}
1870
1871static int
1872icmp6_match(const struct sk_buff *skb,
1873 const struct net_device *in,
1874 const struct net_device *out,
1875 const void *matchinfo,
1876 int offset,
1877 unsigned int protoff,
1878 int *hotdrop)
1879{
1880 struct icmp6hdr _icmp, *ic;
1881 const struct ip6t_icmp *icmpinfo = matchinfo;
1882
1883 /* Must not be a fragment. */
1884 if (offset)
1885 return 0;
1886
1887 ic = skb_header_pointer(skb, protoff, sizeof(_icmp), &_icmp);
1888 if (ic == NULL) {
1889 /* We've been asked to examine this packet, and we
1890 can't. Hence, no choice but to drop. */
1891 duprintf("Dropping evil ICMP tinygram.\n");
1892 *hotdrop = 1;
1893 return 0;
1894 }
1895
1896 return icmp6_type_code_match(icmpinfo->type,
1897 icmpinfo->code[0],
1898 icmpinfo->code[1],
1899 ic->icmp6_type, ic->icmp6_code,
1900 !!(icmpinfo->invflags&IP6T_ICMP_INV));
1901}
1902
1903/* Called when user tries to insert an entry of this type. */
1904static int
1905icmp6_checkentry(const char *tablename,
1906 const struct ip6t_ip6 *ipv6,
1907 void *matchinfo,
1908 unsigned int matchsize,
1909 unsigned int hook_mask)
1910{
1911 const struct ip6t_icmp *icmpinfo = matchinfo;
1912
1913 /* Must specify proto == ICMP, and no unknown invflags */
1914 return ipv6->proto == IPPROTO_ICMPV6
1915 && !(ipv6->invflags & IP6T_INV_PROTO)
1916 && matchsize == IP6T_ALIGN(sizeof(struct ip6t_icmp))
1917 && !(icmpinfo->invflags & ~IP6T_ICMP_INV);
1918}
1919
1920/* The built-in targets: standard (NULL) and error. */
1921static struct ip6t_target ip6t_standard_target = {
1922 .name = IP6T_STANDARD_TARGET,
1923};
1924
1925static struct ip6t_target ip6t_error_target = {
1926 .name = IP6T_ERROR_TARGET,
1927 .target = ip6t_error,
1928};
1929
1930static struct nf_sockopt_ops ip6t_sockopts = {
1931 .pf = PF_INET6,
1932 .set_optmin = IP6T_BASE_CTL,
1933 .set_optmax = IP6T_SO_SET_MAX+1,
1934 .set = do_ip6t_set_ctl,
1935 .get_optmin = IP6T_BASE_CTL,
1936 .get_optmax = IP6T_SO_GET_MAX+1,
1937 .get = do_ip6t_get_ctl,
1938};
1939
1940static struct ip6t_match tcp_matchstruct = {
1941 .name = "tcp",
1942 .match = &tcp_match,
1943 .checkentry = &tcp_checkentry,
1944};
1945
1946static struct ip6t_match udp_matchstruct = {
1947 .name = "udp",
1948 .match = &udp_match,
1949 .checkentry = &udp_checkentry,
1950};
1951
1952static struct ip6t_match icmp6_matchstruct = {
1953 .name = "icmp6",
1954 .match = &icmp6_match,
1955 .checkentry = &icmp6_checkentry,
1956};
1957
1958#ifdef CONFIG_PROC_FS
1959static inline int print_name(const char *i,
1960 off_t start_offset, char *buffer, int length,
1961 off_t *pos, unsigned int *count)
1962{
1963 if ((*count)++ >= start_offset) {
1964 unsigned int namelen;
1965
1966 namelen = sprintf(buffer + *pos, "%s\n",
1967 i + sizeof(struct list_head));
1968 if (*pos + namelen > length) {
1969 /* Stop iterating */
1970 return 1;
1971 }
1972 *pos += namelen;
1973 }
1974 return 0;
1975}
1976
1977static inline int print_target(const struct ip6t_target *t,
1978 off_t start_offset, char *buffer, int length,
1979 off_t *pos, unsigned int *count)
1980{
1981 if (t == &ip6t_standard_target || t == &ip6t_error_target)
1982 return 0;
1983 return print_name((char *)t, start_offset, buffer, length, pos, count);
1984}
1985
1986static int ip6t_get_tables(char *buffer, char **start, off_t offset, int length)
1987{
1988 off_t pos = 0;
1989 unsigned int count = 0;
1990
1991 if (down_interruptible(&ip6t_mutex) != 0)
1992 return 0;
1993
1994 LIST_FIND(&ip6t_tables, print_name, char *,
1995 offset, buffer, length, &pos, &count);
1996
1997 up(&ip6t_mutex);
1998
1999 /* `start' hack - see fs/proc/generic.c line ~105 */
2000 *start=(char *)((unsigned long)count-offset);
2001 return pos;
2002}
2003
2004static int ip6t_get_targets(char *buffer, char **start, off_t offset, int length)
2005{
2006 off_t pos = 0;
2007 unsigned int count = 0;
2008
2009 if (down_interruptible(&ip6t_mutex) != 0)
2010 return 0;
2011
2012 LIST_FIND(&ip6t_target, print_target, struct ip6t_target *,
2013 offset, buffer, length, &pos, &count);
2014
2015 up(&ip6t_mutex);
2016
2017 *start = (char *)((unsigned long)count - offset);
2018 return pos;
2019}
2020
2021static int ip6t_get_matches(char *buffer, char **start, off_t offset, int length)
2022{
2023 off_t pos = 0;
2024 unsigned int count = 0;
2025
2026 if (down_interruptible(&ip6t_mutex) != 0)
2027 return 0;
2028
2029 LIST_FIND(&ip6t_match, print_name, char *,
2030 offset, buffer, length, &pos, &count);
2031
2032 up(&ip6t_mutex);
2033
2034 *start = (char *)((unsigned long)count - offset);
2035 return pos;
2036}
2037
9b5b5cff 2038static const struct { char *name; get_info_t *get_info; } ip6t_proc_entry[] =
1da177e4
LT
2039{ { "ip6_tables_names", ip6t_get_tables },
2040 { "ip6_tables_targets", ip6t_get_targets },
2041 { "ip6_tables_matches", ip6t_get_matches },
2042 { NULL, NULL} };
2043#endif /*CONFIG_PROC_FS*/
2044
2045static int __init init(void)
2046{
2047 int ret;
2048
2049 /* Noone else will be downing sem now, so we won't sleep */
2050 down(&ip6t_mutex);
2051 list_append(&ip6t_target, &ip6t_standard_target);
2052 list_append(&ip6t_target, &ip6t_error_target);
2053 list_append(&ip6t_match, &tcp_matchstruct);
2054 list_append(&ip6t_match, &udp_matchstruct);
2055 list_append(&ip6t_match, &icmp6_matchstruct);
2056 up(&ip6t_mutex);
2057
2058 /* Register setsockopt */
2059 ret = nf_register_sockopt(&ip6t_sockopts);
2060 if (ret < 0) {
2061 duprintf("Unable to register sockopts.\n");
2062 return ret;
2063 }
2064
2065#ifdef CONFIG_PROC_FS
2066 {
2067 struct proc_dir_entry *proc;
2068 int i;
2069
2070 for (i = 0; ip6t_proc_entry[i].name; i++) {
2071 proc = proc_net_create(ip6t_proc_entry[i].name, 0,
2072 ip6t_proc_entry[i].get_info);
2073 if (!proc) {
2074 while (--i >= 0)
2075 proc_net_remove(ip6t_proc_entry[i].name);
2076 nf_unregister_sockopt(&ip6t_sockopts);
2077 return -ENOMEM;
2078 }
2079 proc->owner = THIS_MODULE;
2080 }
2081 }
2082#endif
2083
2084 printk("ip6_tables: (C) 2000-2002 Netfilter core team\n");
2085 return 0;
2086}
2087
2088static void __exit fini(void)
2089{
2090 nf_unregister_sockopt(&ip6t_sockopts);
2091#ifdef CONFIG_PROC_FS
2092 {
2093 int i;
2094 for (i = 0; ip6t_proc_entry[i].name; i++)
2095 proc_net_remove(ip6t_proc_entry[i].name);
2096 }
2097#endif
2098}
2099
e674d0f3
YK
2100/*
2101 * find specified header up to transport protocol header.
2102 * If found target header, the offset to the header is set to *offset
2103 * and return 0. otherwise, return -1.
2104 *
2105 * Notes: - non-1st Fragment Header isn't skipped.
2106 * - ESP header isn't skipped.
2107 * - The target header may be trancated.
2108 */
2109int ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, u8 target)
2110{
2111 unsigned int start = (u8*)(skb->nh.ipv6h + 1) - skb->data;
2112 u8 nexthdr = skb->nh.ipv6h->nexthdr;
2113 unsigned int len = skb->len - start;
2114
2115 while (nexthdr != target) {
2116 struct ipv6_opt_hdr _hdr, *hp;
2117 unsigned int hdrlen;
2118
2119 if ((!ipv6_ext_hdr(nexthdr)) || nexthdr == NEXTHDR_NONE)
2120 return -1;
2121 hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
2122 if (hp == NULL)
2123 return -1;
2124 if (nexthdr == NEXTHDR_FRAGMENT) {
2125 unsigned short _frag_off, *fp;
2126 fp = skb_header_pointer(skb,
2127 start+offsetof(struct frag_hdr,
2128 frag_off),
2129 sizeof(_frag_off),
2130 &_frag_off);
2131 if (fp == NULL)
2132 return -1;
2133
2134 if (ntohs(*fp) & ~0x7)
2135 return -1;
2136 hdrlen = 8;
2137 } else if (nexthdr == NEXTHDR_AUTH)
2138 hdrlen = (hp->hdrlen + 2) << 2;
2139 else
2140 hdrlen = ipv6_optlen(hp);
2141
2142 nexthdr = hp->nexthdr;
2143 len -= hdrlen;
2144 start += hdrlen;
2145 }
2146
2147 *offset = start;
2148 return 0;
2149}
2150
1da177e4
LT
2151EXPORT_SYMBOL(ip6t_register_table);
2152EXPORT_SYMBOL(ip6t_unregister_table);
2153EXPORT_SYMBOL(ip6t_do_table);
2154EXPORT_SYMBOL(ip6t_register_match);
2155EXPORT_SYMBOL(ip6t_unregister_match);
2156EXPORT_SYMBOL(ip6t_register_target);
2157EXPORT_SYMBOL(ip6t_unregister_target);
2158EXPORT_SYMBOL(ip6t_ext_hdr);
e674d0f3 2159EXPORT_SYMBOL(ipv6_find_hdr);
1da177e4
LT
2160
2161module_init(init);
2162module_exit(fini);