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