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