GNU Linux-libre 4.4.288-gnu1
[releases.git] / net / ipv6 / netfilter / ip6_tables.c
1 /*
2  * Packet matching code.
3  *
4  * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5  * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
6  * Copyright (c) 2006-2010 Patrick McHardy <kaber@trash.net>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15 #include <linux/kernel.h>
16 #include <linux/capability.h>
17 #include <linux/in.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/poison.h>
24 #include <linux/icmpv6.h>
25 #include <net/ipv6.h>
26 #include <net/compat.h>
27 #include <asm/uaccess.h>
28 #include <linux/mutex.h>
29 #include <linux/proc_fs.h>
30 #include <linux/err.h>
31 #include <linux/cpumask.h>
32
33 #include <linux/netfilter_ipv6/ip6_tables.h>
34 #include <linux/netfilter/x_tables.h>
35 #include <net/netfilter/nf_log.h>
36 #include "../../netfilter/xt_repldata.h"
37
38 MODULE_LICENSE("GPL");
39 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
40 MODULE_DESCRIPTION("IPv6 packet filter");
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...) pr_info(format , ## args)
48 #else
49 #define dprintf(format, args...)
50 #endif
51
52 #ifdef DEBUG_IP_FIREWALL_USER
53 #define duprintf(format, args...) pr_info(format , ## args)
54 #else
55 #define duprintf(format, args...)
56 #endif
57
58 #ifdef CONFIG_NETFILTER_DEBUG
59 #define IP_NF_ASSERT(x) WARN_ON(!(x))
60 #else
61 #define IP_NF_ASSERT(x)
62 #endif
63
64 #if 0
65 /* All the better to debug you with... */
66 #define static
67 #define inline
68 #endif
69
70 void *ip6t_alloc_initial_table(const struct xt_table *info)
71 {
72         return xt_alloc_initial_table(ip6t, IP6T);
73 }
74 EXPORT_SYMBOL_GPL(ip6t_alloc_initial_table);
75
76 /*
77    We keep a set of rules for each CPU, so we can avoid write-locking
78    them in the softirq when updating the counters and therefore
79    only need to read-lock in the softirq; doing a write_lock_bh() in user
80    context stops packets coming through and allows user context to read
81    the counters or update the rules.
82
83    Hence the start of any table is given by get_table() below.  */
84
85 /* Returns whether matches rule or not. */
86 /* Performance critical - called for every packet */
87 static inline bool
88 ip6_packet_match(const struct sk_buff *skb,
89                  const char *indev,
90                  const char *outdev,
91                  const struct ip6t_ip6 *ip6info,
92                  unsigned int *protoff,
93                  int *fragoff, bool *hotdrop)
94 {
95         unsigned long ret;
96         const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
97
98 #define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg)))
99
100         if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
101                                        &ip6info->src), IP6T_INV_SRCIP) ||
102             FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
103                                        &ip6info->dst), IP6T_INV_DSTIP)) {
104                 dprintf("Source or dest mismatch.\n");
105 /*
106                 dprintf("SRC: %u. Mask: %u. Target: %u.%s\n", ip->saddr,
107                         ipinfo->smsk.s_addr, ipinfo->src.s_addr,
108                         ipinfo->invflags & IP6T_INV_SRCIP ? " (INV)" : "");
109                 dprintf("DST: %u. Mask: %u. Target: %u.%s\n", ip->daddr,
110                         ipinfo->dmsk.s_addr, ipinfo->dst.s_addr,
111                         ipinfo->invflags & IP6T_INV_DSTIP ? " (INV)" : "");*/
112                 return false;
113         }
114
115         ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
116
117         if (FWINV(ret != 0, IP6T_INV_VIA_IN)) {
118                 dprintf("VIA in mismatch (%s vs %s).%s\n",
119                         indev, ip6info->iniface,
120                         ip6info->invflags & IP6T_INV_VIA_IN ? " (INV)" : "");
121                 return false;
122         }
123
124         ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
125
126         if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) {
127                 dprintf("VIA out mismatch (%s vs %s).%s\n",
128                         outdev, ip6info->outiface,
129                         ip6info->invflags & IP6T_INV_VIA_OUT ? " (INV)" : "");
130                 return false;
131         }
132
133 /* ... might want to do something with class and flowlabel here ... */
134
135         /* look for the desired protocol header */
136         if (ip6info->flags & IP6T_F_PROTO) {
137                 int protohdr;
138                 unsigned short _frag_off;
139
140                 protohdr = ipv6_find_hdr(skb, protoff, -1, &_frag_off, NULL);
141                 if (protohdr < 0) {
142                         if (_frag_off == 0)
143                                 *hotdrop = true;
144                         return false;
145                 }
146                 *fragoff = _frag_off;
147
148                 dprintf("Packet protocol %hi ?= %s%hi.\n",
149                                 protohdr,
150                                 ip6info->invflags & IP6T_INV_PROTO ? "!":"",
151                                 ip6info->proto);
152
153                 if (ip6info->proto == protohdr) {
154                         if (ip6info->invflags & IP6T_INV_PROTO)
155                                 return false;
156
157                         return true;
158                 }
159
160                 /* We need match for the '-p all', too! */
161                 if ((ip6info->proto != 0) &&
162                         !(ip6info->invflags & IP6T_INV_PROTO))
163                         return false;
164         }
165         return true;
166 }
167
168 /* should be ip6 safe */
169 static bool
170 ip6_checkentry(const struct ip6t_ip6 *ipv6)
171 {
172         if (ipv6->flags & ~IP6T_F_MASK) {
173                 duprintf("Unknown flag bits set: %08X\n",
174                          ipv6->flags & ~IP6T_F_MASK);
175                 return false;
176         }
177         if (ipv6->invflags & ~IP6T_INV_MASK) {
178                 duprintf("Unknown invflag bits set: %08X\n",
179                          ipv6->invflags & ~IP6T_INV_MASK);
180                 return false;
181         }
182         return true;
183 }
184
185 static unsigned int
186 ip6t_error(struct sk_buff *skb, const struct xt_action_param *par)
187 {
188         net_info_ratelimited("error: `%s'\n", (const char *)par->targinfo);
189
190         return NF_DROP;
191 }
192
193 static inline struct ip6t_entry *
194 get_entry(const void *base, unsigned int offset)
195 {
196         return (struct ip6t_entry *)(base + offset);
197 }
198
199 /* All zeroes == unconditional rule. */
200 /* Mildly perf critical (only if packet tracing is on) */
201 static inline bool unconditional(const struct ip6t_entry *e)
202 {
203         static const struct ip6t_ip6 uncond;
204
205         return e->target_offset == sizeof(struct ip6t_entry) &&
206                memcmp(&e->ipv6, &uncond, sizeof(uncond)) == 0;
207 }
208
209 static inline const struct xt_entry_target *
210 ip6t_get_target_c(const struct ip6t_entry *e)
211 {
212         return ip6t_get_target((struct ip6t_entry *)e);
213 }
214
215 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
216 /* This cries for unification! */
217 static const char *const hooknames[] = {
218         [NF_INET_PRE_ROUTING]           = "PREROUTING",
219         [NF_INET_LOCAL_IN]              = "INPUT",
220         [NF_INET_FORWARD]               = "FORWARD",
221         [NF_INET_LOCAL_OUT]             = "OUTPUT",
222         [NF_INET_POST_ROUTING]          = "POSTROUTING",
223 };
224
225 enum nf_ip_trace_comments {
226         NF_IP6_TRACE_COMMENT_RULE,
227         NF_IP6_TRACE_COMMENT_RETURN,
228         NF_IP6_TRACE_COMMENT_POLICY,
229 };
230
231 static const char *const comments[] = {
232         [NF_IP6_TRACE_COMMENT_RULE]     = "rule",
233         [NF_IP6_TRACE_COMMENT_RETURN]   = "return",
234         [NF_IP6_TRACE_COMMENT_POLICY]   = "policy",
235 };
236
237 static struct nf_loginfo trace_loginfo = {
238         .type = NF_LOG_TYPE_LOG,
239         .u = {
240                 .log = {
241                         .level = LOGLEVEL_WARNING,
242                         .logflags = NF_LOG_MASK,
243                 },
244         },
245 };
246
247 /* Mildly perf critical (only if packet tracing is on) */
248 static inline int
249 get_chainname_rulenum(const struct ip6t_entry *s, const struct ip6t_entry *e,
250                       const char *hookname, const char **chainname,
251                       const char **comment, unsigned int *rulenum)
252 {
253         const struct xt_standard_target *t = (void *)ip6t_get_target_c(s);
254
255         if (strcmp(t->target.u.kernel.target->name, XT_ERROR_TARGET) == 0) {
256                 /* Head of user chain: ERROR target with chainname */
257                 *chainname = t->target.data;
258                 (*rulenum) = 0;
259         } else if (s == e) {
260                 (*rulenum)++;
261
262                 if (unconditional(s) &&
263                     strcmp(t->target.u.kernel.target->name,
264                            XT_STANDARD_TARGET) == 0 &&
265                     t->verdict < 0) {
266                         /* Tail of chains: STANDARD target (return/policy) */
267                         *comment = *chainname == hookname
268                                 ? comments[NF_IP6_TRACE_COMMENT_POLICY]
269                                 : comments[NF_IP6_TRACE_COMMENT_RETURN];
270                 }
271                 return 1;
272         } else
273                 (*rulenum)++;
274
275         return 0;
276 }
277
278 static void trace_packet(struct net *net,
279                          const struct sk_buff *skb,
280                          unsigned int hook,
281                          const struct net_device *in,
282                          const struct net_device *out,
283                          const char *tablename,
284                          const struct xt_table_info *private,
285                          const struct ip6t_entry *e)
286 {
287         const struct ip6t_entry *root;
288         const char *hookname, *chainname, *comment;
289         const struct ip6t_entry *iter;
290         unsigned int rulenum = 0;
291
292         root = get_entry(private->entries, private->hook_entry[hook]);
293
294         hookname = chainname = hooknames[hook];
295         comment = comments[NF_IP6_TRACE_COMMENT_RULE];
296
297         xt_entry_foreach(iter, root, private->size - private->hook_entry[hook])
298                 if (get_chainname_rulenum(iter, e, hookname,
299                     &chainname, &comment, &rulenum) != 0)
300                         break;
301
302         nf_log_trace(net, AF_INET6, hook, skb, in, out, &trace_loginfo,
303                      "TRACE: %s:%s:%s:%u ",
304                      tablename, chainname, comment, rulenum);
305 }
306 #endif
307
308 static inline struct ip6t_entry *
309 ip6t_next_entry(const struct ip6t_entry *entry)
310 {
311         return (void *)entry + entry->next_offset;
312 }
313
314 /* Returns one of the generic firewall policies, like NF_ACCEPT. */
315 unsigned int
316 ip6t_do_table(struct sk_buff *skb,
317               const struct nf_hook_state *state,
318               struct xt_table *table)
319 {
320         unsigned int hook = state->hook;
321         static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
322         /* Initializing verdict to NF_DROP keeps gcc happy. */
323         unsigned int verdict = NF_DROP;
324         const char *indev, *outdev;
325         const void *table_base;
326         struct ip6t_entry *e, **jumpstack;
327         unsigned int stackidx, cpu;
328         const struct xt_table_info *private;
329         struct xt_action_param acpar;
330         unsigned int addend;
331
332         /* Initialization */
333         stackidx = 0;
334         indev = state->in ? state->in->name : nulldevname;
335         outdev = state->out ? state->out->name : nulldevname;
336         /* We handle fragments by dealing with the first fragment as
337          * if it was a normal packet.  All other fragments are treated
338          * normally, except that they will NEVER match rules that ask
339          * things we don't know, ie. tcp syn flag or ports).  If the
340          * rule is also a fragment-specific rule, non-fragments won't
341          * match it. */
342         acpar.hotdrop = false;
343         acpar.net     = state->net;
344         acpar.in      = state->in;
345         acpar.out     = state->out;
346         acpar.family  = NFPROTO_IPV6;
347         acpar.hooknum = hook;
348
349         IP_NF_ASSERT(table->valid_hooks & (1 << hook));
350
351         local_bh_disable();
352         addend = xt_write_recseq_begin();
353         private = table->private;
354         /*
355          * Ensure we load private-> members after we've fetched the base
356          * pointer.
357          */
358         smp_read_barrier_depends();
359         cpu        = smp_processor_id();
360         table_base = private->entries;
361         jumpstack  = (struct ip6t_entry **)private->jumpstack[cpu];
362
363         /* Switch to alternate jumpstack if we're being invoked via TEE.
364          * TEE issues XT_CONTINUE verdict on original skb so we must not
365          * clobber the jumpstack.
366          *
367          * For recursion via REJECT or SYNPROXY the stack will be clobbered
368          * but it is no problem since absolute verdict is issued by these.
369          */
370         if (static_key_false(&xt_tee_enabled))
371                 jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
372
373         e = get_entry(table_base, private->hook_entry[hook]);
374
375         do {
376                 const struct xt_entry_target *t;
377                 const struct xt_entry_match *ematch;
378                 struct xt_counters *counter;
379
380                 IP_NF_ASSERT(e);
381                 acpar.thoff = 0;
382                 if (!ip6_packet_match(skb, indev, outdev, &e->ipv6,
383                     &acpar.thoff, &acpar.fragoff, &acpar.hotdrop)) {
384  no_match:
385                         e = ip6t_next_entry(e);
386                         continue;
387                 }
388
389                 xt_ematch_foreach(ematch, e) {
390                         acpar.match     = ematch->u.kernel.match;
391                         acpar.matchinfo = ematch->data;
392                         if (!acpar.match->match(skb, &acpar))
393                                 goto no_match;
394                 }
395
396                 counter = xt_get_this_cpu_counter(&e->counters);
397                 ADD_COUNTER(*counter, skb->len, 1);
398
399                 t = ip6t_get_target_c(e);
400                 IP_NF_ASSERT(t->u.kernel.target);
401
402 #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE)
403                 /* The packet is traced: log it */
404                 if (unlikely(skb->nf_trace))
405                         trace_packet(state->net, skb, hook, state->in,
406                                      state->out, table->name, private, e);
407 #endif
408                 /* Standard target? */
409                 if (!t->u.kernel.target->target) {
410                         int v;
411
412                         v = ((struct xt_standard_target *)t)->verdict;
413                         if (v < 0) {
414                                 /* Pop from stack? */
415                                 if (v != XT_RETURN) {
416                                         verdict = (unsigned int)(-v) - 1;
417                                         break;
418                                 }
419                                 if (stackidx == 0)
420                                         e = get_entry(table_base,
421                                             private->underflow[hook]);
422                                 else
423                                         e = ip6t_next_entry(jumpstack[--stackidx]);
424                                 continue;
425                         }
426                         if (table_base + v != ip6t_next_entry(e) &&
427                             !(e->ipv6.flags & IP6T_F_GOTO)) {
428                                 if (unlikely(stackidx >= private->stacksize)) {
429                                         verdict = NF_DROP;
430                                         break;
431                                 }
432                                 jumpstack[stackidx++] = e;
433                         }
434
435                         e = get_entry(table_base, v);
436                         continue;
437                 }
438
439                 acpar.target   = t->u.kernel.target;
440                 acpar.targinfo = t->data;
441
442                 verdict = t->u.kernel.target->target(skb, &acpar);
443                 if (verdict == XT_CONTINUE)
444                         e = ip6t_next_entry(e);
445                 else
446                         /* Verdict */
447                         break;
448         } while (!acpar.hotdrop);
449
450         xt_write_recseq_end(addend);
451         local_bh_enable();
452
453 #ifdef DEBUG_ALLOW_ALL
454         return NF_ACCEPT;
455 #else
456         if (acpar.hotdrop)
457                 return NF_DROP;
458         else return verdict;
459 #endif
460 }
461
462 /* Figures out from what hook each rule can be called: returns 0 if
463    there are loops.  Puts hook bitmask in comefrom. */
464 static int
465 mark_source_chains(const struct xt_table_info *newinfo,
466                    unsigned int valid_hooks, void *entry0,
467                    unsigned int *offsets)
468 {
469         unsigned int hook;
470
471         /* No recursion; use packet counter to save back ptrs (reset
472            to 0 as we leave), and comefrom to save source hook bitmask */
473         for (hook = 0; hook < NF_INET_NUMHOOKS; hook++) {
474                 unsigned int pos = newinfo->hook_entry[hook];
475                 struct ip6t_entry *e = (struct ip6t_entry *)(entry0 + pos);
476
477                 if (!(valid_hooks & (1 << hook)))
478                         continue;
479
480                 /* Set initial back pointer. */
481                 e->counters.pcnt = pos;
482
483                 for (;;) {
484                         const struct xt_standard_target *t
485                                 = (void *)ip6t_get_target_c(e);
486                         int visited = e->comefrom & (1 << hook);
487
488                         if (e->comefrom & (1 << NF_INET_NUMHOOKS)) {
489                                 pr_err("iptables: loop hook %u pos %u %08X.\n",
490                                        hook, pos, e->comefrom);
491                                 return 0;
492                         }
493                         e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS));
494
495                         /* Unconditional return/END. */
496                         if ((unconditional(e) &&
497                              (strcmp(t->target.u.user.name,
498                                      XT_STANDARD_TARGET) == 0) &&
499                              t->verdict < 0) || visited) {
500                                 unsigned int oldpos, size;
501
502                                 if ((strcmp(t->target.u.user.name,
503                                             XT_STANDARD_TARGET) == 0) &&
504                                     t->verdict < -NF_MAX_VERDICT - 1) {
505                                         duprintf("mark_source_chains: bad "
506                                                 "negative verdict (%i)\n",
507                                                                 t->verdict);
508                                         return 0;
509                                 }
510
511                                 /* Return: backtrack through the last
512                                    big jump. */
513                                 do {
514                                         e->comefrom ^= (1<<NF_INET_NUMHOOKS);
515 #ifdef DEBUG_IP_FIREWALL_USER
516                                         if (e->comefrom
517                                             & (1 << NF_INET_NUMHOOKS)) {
518                                                 duprintf("Back unset "
519                                                          "on hook %u "
520                                                          "rule %u\n",
521                                                          hook, pos);
522                                         }
523 #endif
524                                         oldpos = pos;
525                                         pos = e->counters.pcnt;
526                                         e->counters.pcnt = 0;
527
528                                         /* We're at the start. */
529                                         if (pos == oldpos)
530                                                 goto next;
531
532                                         e = (struct ip6t_entry *)
533                                                 (entry0 + pos);
534                                 } while (oldpos == pos + e->next_offset);
535
536                                 /* Move along one */
537                                 size = e->next_offset;
538                                 e = (struct ip6t_entry *)
539                                         (entry0 + pos + size);
540                                 if (pos + size >= newinfo->size)
541                                         return 0;
542                                 e->counters.pcnt = pos;
543                                 pos += size;
544                         } else {
545                                 int newpos = t->verdict;
546
547                                 if (strcmp(t->target.u.user.name,
548                                            XT_STANDARD_TARGET) == 0 &&
549                                     newpos >= 0) {
550                                         if (newpos > newinfo->size -
551                                                 sizeof(struct ip6t_entry)) {
552                                                 duprintf("mark_source_chains: "
553                                                         "bad verdict (%i)\n",
554                                                                 newpos);
555                                                 return 0;
556                                         }
557                                         /* This a jump; chase it. */
558                                         duprintf("Jump rule %u -> %u\n",
559                                                  pos, newpos);
560                                         if (!xt_find_jump_offset(offsets, newpos,
561                                                                  newinfo->number))
562                                                 return 0;
563                                         e = (struct ip6t_entry *)
564                                                 (entry0 + newpos);
565                                 } else {
566                                         /* ... this is a fallthru */
567                                         newpos = pos + e->next_offset;
568                                         if (newpos >= newinfo->size)
569                                                 return 0;
570                                 }
571                                 e = (struct ip6t_entry *)
572                                         (entry0 + newpos);
573                                 e->counters.pcnt = pos;
574                                 pos = newpos;
575                         }
576                 }
577 next:
578                 duprintf("Finished chain %u\n", hook);
579         }
580         return 1;
581 }
582
583 static void cleanup_match(struct xt_entry_match *m, struct net *net)
584 {
585         struct xt_mtdtor_param par;
586
587         par.net       = net;
588         par.match     = m->u.kernel.match;
589         par.matchinfo = m->data;
590         par.family    = NFPROTO_IPV6;
591         if (par.match->destroy != NULL)
592                 par.match->destroy(&par);
593         module_put(par.match->me);
594 }
595
596 static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
597 {
598         const struct ip6t_ip6 *ipv6 = par->entryinfo;
599         int ret;
600
601         par->match     = m->u.kernel.match;
602         par->matchinfo = m->data;
603
604         ret = xt_check_match(par, m->u.match_size - sizeof(*m),
605                              ipv6->proto, ipv6->invflags & IP6T_INV_PROTO);
606         if (ret < 0) {
607                 duprintf("ip_tables: check failed for `%s'.\n",
608                          par.match->name);
609                 return ret;
610         }
611         return 0;
612 }
613
614 static int
615 find_check_match(struct xt_entry_match *m, struct xt_mtchk_param *par)
616 {
617         struct xt_match *match;
618         int ret;
619
620         match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
621                                       m->u.user.revision);
622         if (IS_ERR(match)) {
623                 duprintf("find_check_match: `%s' not found\n", m->u.user.name);
624                 return PTR_ERR(match);
625         }
626         m->u.kernel.match = match;
627
628         ret = check_match(m, par);
629         if (ret)
630                 goto err;
631
632         return 0;
633 err:
634         module_put(m->u.kernel.match->me);
635         return ret;
636 }
637
638 static int check_target(struct ip6t_entry *e, struct net *net, const char *name)
639 {
640         struct xt_entry_target *t = ip6t_get_target(e);
641         struct xt_tgchk_param par = {
642                 .net       = net,
643                 .table     = name,
644                 .entryinfo = e,
645                 .target    = t->u.kernel.target,
646                 .targinfo  = t->data,
647                 .hook_mask = e->comefrom,
648                 .family    = NFPROTO_IPV6,
649         };
650         int ret;
651
652         t = ip6t_get_target(e);
653         ret = xt_check_target(&par, t->u.target_size - sizeof(*t),
654               e->ipv6.proto, e->ipv6.invflags & IP6T_INV_PROTO);
655         if (ret < 0) {
656                 duprintf("ip_tables: check failed for `%s'.\n",
657                          t->u.kernel.target->name);
658                 return ret;
659         }
660         return 0;
661 }
662
663 static int
664 find_check_entry(struct ip6t_entry *e, struct net *net, const char *name,
665                  unsigned int size,
666                  struct xt_percpu_counter_alloc_state *alloc_state)
667 {
668         struct xt_entry_target *t;
669         struct xt_target *target;
670         int ret;
671         unsigned int j;
672         struct xt_mtchk_param mtpar;
673         struct xt_entry_match *ematch;
674
675         if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
676                 return -ENOMEM;
677
678         j = 0;
679         memset(&mtpar, 0, sizeof(mtpar));
680         mtpar.net       = net;
681         mtpar.table     = name;
682         mtpar.entryinfo = &e->ipv6;
683         mtpar.hook_mask = e->comefrom;
684         mtpar.family    = NFPROTO_IPV6;
685         xt_ematch_foreach(ematch, e) {
686                 ret = find_check_match(ematch, &mtpar);
687                 if (ret != 0)
688                         goto cleanup_matches;
689                 ++j;
690         }
691
692         t = ip6t_get_target(e);
693         target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
694                                         t->u.user.revision);
695         if (IS_ERR(target)) {
696                 duprintf("find_check_entry: `%s' not found\n", t->u.user.name);
697                 ret = PTR_ERR(target);
698                 goto cleanup_matches;
699         }
700         t->u.kernel.target = target;
701
702         ret = check_target(e, net, name);
703         if (ret)
704                 goto err;
705         return 0;
706  err:
707         module_put(t->u.kernel.target->me);
708  cleanup_matches:
709         xt_ematch_foreach(ematch, e) {
710                 if (j-- == 0)
711                         break;
712                 cleanup_match(ematch, net);
713         }
714
715         xt_percpu_counter_free(&e->counters);
716
717         return ret;
718 }
719
720 static bool check_underflow(const struct ip6t_entry *e)
721 {
722         const struct xt_entry_target *t;
723         unsigned int verdict;
724
725         if (!unconditional(e))
726                 return false;
727         t = ip6t_get_target_c(e);
728         if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0)
729                 return false;
730         verdict = ((struct xt_standard_target *)t)->verdict;
731         verdict = -verdict - 1;
732         return verdict == NF_DROP || verdict == NF_ACCEPT;
733 }
734
735 static int
736 check_entry_size_and_hooks(struct ip6t_entry *e,
737                            struct xt_table_info *newinfo,
738                            const unsigned char *base,
739                            const unsigned char *limit,
740                            const unsigned int *hook_entries,
741                            const unsigned int *underflows,
742                            unsigned int valid_hooks)
743 {
744         unsigned int h;
745         int err;
746
747         if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 ||
748             (unsigned char *)e + sizeof(struct ip6t_entry) >= limit ||
749             (unsigned char *)e + e->next_offset > limit) {
750                 duprintf("Bad offset %p\n", e);
751                 return -EINVAL;
752         }
753
754         if (e->next_offset
755             < sizeof(struct ip6t_entry) + sizeof(struct xt_entry_target)) {
756                 duprintf("checking: element %p size %u\n",
757                          e, e->next_offset);
758                 return -EINVAL;
759         }
760
761         if (!ip6_checkentry(&e->ipv6))
762                 return -EINVAL;
763
764         err = xt_check_entry_offsets(e, e->elems, e->target_offset,
765                                      e->next_offset);
766         if (err)
767                 return err;
768
769         /* Check hooks & underflows */
770         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
771                 if (!(valid_hooks & (1 << h)))
772                         continue;
773                 if ((unsigned char *)e - base == hook_entries[h])
774                         newinfo->hook_entry[h] = hook_entries[h];
775                 if ((unsigned char *)e - base == underflows[h]) {
776                         if (!check_underflow(e)) {
777                                 pr_debug("Underflows must be unconditional and "
778                                          "use the STANDARD target with "
779                                          "ACCEPT/DROP\n");
780                                 return -EINVAL;
781                         }
782                         newinfo->underflow[h] = underflows[h];
783                 }
784         }
785
786         /* Clear counters and comefrom */
787         e->counters = ((struct xt_counters) { 0, 0 });
788         e->comefrom = 0;
789         return 0;
790 }
791
792 static void cleanup_entry(struct ip6t_entry *e, struct net *net)
793 {
794         struct xt_tgdtor_param par;
795         struct xt_entry_target *t;
796         struct xt_entry_match *ematch;
797
798         /* Cleanup all matches */
799         xt_ematch_foreach(ematch, e)
800                 cleanup_match(ematch, net);
801         t = ip6t_get_target(e);
802
803         par.net      = net;
804         par.target   = t->u.kernel.target;
805         par.targinfo = t->data;
806         par.family   = NFPROTO_IPV6;
807         if (par.target->destroy != NULL)
808                 par.target->destroy(&par);
809         module_put(par.target->me);
810         xt_percpu_counter_free(&e->counters);
811 }
812
813 /* Checks and translates the user-supplied table segment (held in
814    newinfo) */
815 static int
816 translate_table(struct net *net, struct xt_table_info *newinfo, void *entry0,
817                 const struct ip6t_replace *repl)
818 {
819         struct xt_percpu_counter_alloc_state alloc_state = { 0 };
820         struct ip6t_entry *iter;
821         unsigned int *offsets;
822         unsigned int i;
823         int ret = 0;
824
825         newinfo->size = repl->size;
826         newinfo->number = repl->num_entries;
827
828         /* Init all hooks to impossible value. */
829         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
830                 newinfo->hook_entry[i] = 0xFFFFFFFF;
831                 newinfo->underflow[i] = 0xFFFFFFFF;
832         }
833
834         duprintf("translate_table: size %u\n", newinfo->size);
835         offsets = xt_alloc_entry_offsets(newinfo->number);
836         if (!offsets)
837                 return -ENOMEM;
838         i = 0;
839         /* Walk through entries, checking offsets. */
840         xt_entry_foreach(iter, entry0, newinfo->size) {
841                 ret = check_entry_size_and_hooks(iter, newinfo, entry0,
842                                                  entry0 + repl->size,
843                                                  repl->hook_entry,
844                                                  repl->underflow,
845                                                  repl->valid_hooks);
846                 if (ret != 0)
847                         goto out_free;
848                 if (i < repl->num_entries)
849                         offsets[i] = (void *)iter - entry0;
850                 ++i;
851                 if (strcmp(ip6t_get_target(iter)->u.user.name,
852                     XT_ERROR_TARGET) == 0)
853                         ++newinfo->stacksize;
854         }
855
856         ret = -EINVAL;
857         if (i != repl->num_entries) {
858                 duprintf("translate_table: %u not %u entries\n",
859                          i, repl->num_entries);
860                 goto out_free;
861         }
862
863         /* Check hooks all assigned */
864         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
865                 /* Only hooks which are valid */
866                 if (!(repl->valid_hooks & (1 << i)))
867                         continue;
868                 if (newinfo->hook_entry[i] == 0xFFFFFFFF) {
869                         duprintf("Invalid hook entry %u %u\n",
870                                  i, repl->hook_entry[i]);
871                         goto out_free;
872                 }
873                 if (newinfo->underflow[i] == 0xFFFFFFFF) {
874                         duprintf("Invalid underflow %u %u\n",
875                                  i, repl->underflow[i]);
876                         goto out_free;
877                 }
878         }
879
880         if (!mark_source_chains(newinfo, repl->valid_hooks, entry0, offsets)) {
881                 ret = -ELOOP;
882                 goto out_free;
883         }
884         kvfree(offsets);
885
886         /* Finally, each sanity check must pass */
887         i = 0;
888         xt_entry_foreach(iter, entry0, newinfo->size) {
889                 ret = find_check_entry(iter, net, repl->name, repl->size,
890                                        &alloc_state);
891                 if (ret != 0)
892                         break;
893                 ++i;
894         }
895
896         if (ret != 0) {
897                 xt_entry_foreach(iter, entry0, newinfo->size) {
898                         if (i-- == 0)
899                                 break;
900                         cleanup_entry(iter, net);
901                 }
902                 return ret;
903         }
904
905         return ret;
906  out_free:
907         kvfree(offsets);
908         return ret;
909 }
910
911 static void
912 get_counters(const struct xt_table_info *t,
913              struct xt_counters counters[])
914 {
915         struct ip6t_entry *iter;
916         unsigned int cpu;
917         unsigned int i;
918
919         for_each_possible_cpu(cpu) {
920                 seqcount_t *s = &per_cpu(xt_recseq, cpu);
921
922                 i = 0;
923                 xt_entry_foreach(iter, t->entries, t->size) {
924                         struct xt_counters *tmp;
925                         u64 bcnt, pcnt;
926                         unsigned int start;
927
928                         tmp = xt_get_per_cpu_counter(&iter->counters, cpu);
929                         do {
930                                 start = read_seqcount_begin(s);
931                                 bcnt = tmp->bcnt;
932                                 pcnt = tmp->pcnt;
933                         } while (read_seqcount_retry(s, start));
934
935                         ADD_COUNTER(counters[i], bcnt, pcnt);
936                         ++i;
937                 }
938         }
939 }
940
941 static struct xt_counters *alloc_counters(const struct xt_table *table)
942 {
943         unsigned int countersize;
944         struct xt_counters *counters;
945         const struct xt_table_info *private = table->private;
946
947         /* We need atomic snapshot of counters: rest doesn't change
948            (other than comefrom, which userspace doesn't care
949            about). */
950         countersize = sizeof(struct xt_counters) * private->number;
951         counters = vzalloc(countersize);
952
953         if (counters == NULL)
954                 return ERR_PTR(-ENOMEM);
955
956         get_counters(private, counters);
957
958         return counters;
959 }
960
961 static int
962 copy_entries_to_user(unsigned int total_size,
963                      const struct xt_table *table,
964                      void __user *userptr)
965 {
966         unsigned int off, num;
967         const struct ip6t_entry *e;
968         struct xt_counters *counters;
969         const struct xt_table_info *private = table->private;
970         int ret = 0;
971         const void *loc_cpu_entry;
972
973         counters = alloc_counters(table);
974         if (IS_ERR(counters))
975                 return PTR_ERR(counters);
976
977         loc_cpu_entry = private->entries;
978         if (copy_to_user(userptr, loc_cpu_entry, total_size) != 0) {
979                 ret = -EFAULT;
980                 goto free_counters;
981         }
982
983         /* FIXME: use iterator macros --RR */
984         /* ... then go back and fix counters and names */
985         for (off = 0, num = 0; off < total_size; off += e->next_offset, num++){
986                 unsigned int i;
987                 const struct xt_entry_match *m;
988                 const struct xt_entry_target *t;
989
990                 e = (struct ip6t_entry *)(loc_cpu_entry + off);
991                 if (copy_to_user(userptr + off
992                                  + offsetof(struct ip6t_entry, counters),
993                                  &counters[num],
994                                  sizeof(counters[num])) != 0) {
995                         ret = -EFAULT;
996                         goto free_counters;
997                 }
998
999                 for (i = sizeof(struct ip6t_entry);
1000                      i < e->target_offset;
1001                      i += m->u.match_size) {
1002                         m = (void *)e + i;
1003
1004                         if (copy_to_user(userptr + off + i
1005                                          + offsetof(struct xt_entry_match,
1006                                                     u.user.name),
1007                                          m->u.kernel.match->name,
1008                                          strlen(m->u.kernel.match->name)+1)
1009                             != 0) {
1010                                 ret = -EFAULT;
1011                                 goto free_counters;
1012                         }
1013                 }
1014
1015                 t = ip6t_get_target_c(e);
1016                 if (copy_to_user(userptr + off + e->target_offset
1017                                  + offsetof(struct xt_entry_target,
1018                                             u.user.name),
1019                                  t->u.kernel.target->name,
1020                                  strlen(t->u.kernel.target->name)+1) != 0) {
1021                         ret = -EFAULT;
1022                         goto free_counters;
1023                 }
1024         }
1025
1026  free_counters:
1027         vfree(counters);
1028         return ret;
1029 }
1030
1031 #ifdef CONFIG_COMPAT
1032 static void compat_standard_from_user(void *dst, const void *src)
1033 {
1034         int v = *(compat_int_t *)src;
1035
1036         if (v > 0)
1037                 v += xt_compat_calc_jump(AF_INET6, v);
1038         memcpy(dst, &v, sizeof(v));
1039 }
1040
1041 static int compat_standard_to_user(void __user *dst, const void *src)
1042 {
1043         compat_int_t cv = *(int *)src;
1044
1045         if (cv > 0)
1046                 cv -= xt_compat_calc_jump(AF_INET6, cv);
1047         return copy_to_user(dst, &cv, sizeof(cv)) ? -EFAULT : 0;
1048 }
1049
1050 static int compat_calc_entry(const struct ip6t_entry *e,
1051                              const struct xt_table_info *info,
1052                              const void *base, struct xt_table_info *newinfo)
1053 {
1054         const struct xt_entry_match *ematch;
1055         const struct xt_entry_target *t;
1056         unsigned int entry_offset;
1057         int off, i, ret;
1058
1059         off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1060         entry_offset = (void *)e - base;
1061         xt_ematch_foreach(ematch, e)
1062                 off += xt_compat_match_offset(ematch->u.kernel.match);
1063         t = ip6t_get_target_c(e);
1064         off += xt_compat_target_offset(t->u.kernel.target);
1065         newinfo->size -= off;
1066         ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1067         if (ret)
1068                 return ret;
1069
1070         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1071                 if (info->hook_entry[i] &&
1072                     (e < (struct ip6t_entry *)(base + info->hook_entry[i])))
1073                         newinfo->hook_entry[i] -= off;
1074                 if (info->underflow[i] &&
1075                     (e < (struct ip6t_entry *)(base + info->underflow[i])))
1076                         newinfo->underflow[i] -= off;
1077         }
1078         return 0;
1079 }
1080
1081 static int compat_table_info(const struct xt_table_info *info,
1082                              struct xt_table_info *newinfo)
1083 {
1084         struct ip6t_entry *iter;
1085         const void *loc_cpu_entry;
1086         int ret;
1087
1088         if (!newinfo || !info)
1089                 return -EINVAL;
1090
1091         /* we dont care about newinfo->entries */
1092         memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
1093         newinfo->initial_entries = 0;
1094         loc_cpu_entry = info->entries;
1095         xt_compat_init_offsets(AF_INET6, info->number);
1096         xt_entry_foreach(iter, loc_cpu_entry, info->size) {
1097                 ret = compat_calc_entry(iter, info, loc_cpu_entry, newinfo);
1098                 if (ret != 0)
1099                         return ret;
1100         }
1101         return 0;
1102 }
1103 #endif
1104
1105 static int get_info(struct net *net, void __user *user,
1106                     const int *len, int compat)
1107 {
1108         char name[XT_TABLE_MAXNAMELEN];
1109         struct xt_table *t;
1110         int ret;
1111
1112         if (*len != sizeof(struct ip6t_getinfo)) {
1113                 duprintf("length %u != %zu\n", *len,
1114                          sizeof(struct ip6t_getinfo));
1115                 return -EINVAL;
1116         }
1117
1118         if (copy_from_user(name, user, sizeof(name)) != 0)
1119                 return -EFAULT;
1120
1121         name[XT_TABLE_MAXNAMELEN-1] = '\0';
1122 #ifdef CONFIG_COMPAT
1123         if (compat)
1124                 xt_compat_lock(AF_INET6);
1125 #endif
1126         t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1127                                     "ip6table_%s", name);
1128         if (!IS_ERR_OR_NULL(t)) {
1129                 struct ip6t_getinfo info;
1130                 const struct xt_table_info *private = t->private;
1131 #ifdef CONFIG_COMPAT
1132                 struct xt_table_info tmp;
1133
1134                 if (compat) {
1135                         ret = compat_table_info(private, &tmp);
1136                         xt_compat_flush_offsets(AF_INET6);
1137                         private = &tmp;
1138                 }
1139 #endif
1140                 memset(&info, 0, sizeof(info));
1141                 info.valid_hooks = t->valid_hooks;
1142                 memcpy(info.hook_entry, private->hook_entry,
1143                        sizeof(info.hook_entry));
1144                 memcpy(info.underflow, private->underflow,
1145                        sizeof(info.underflow));
1146                 info.num_entries = private->number;
1147                 info.size = private->size;
1148                 strcpy(info.name, name);
1149
1150                 if (copy_to_user(user, &info, *len) != 0)
1151                         ret = -EFAULT;
1152                 else
1153                         ret = 0;
1154
1155                 xt_table_unlock(t);
1156                 module_put(t->me);
1157         } else
1158                 ret = t ? PTR_ERR(t) : -ENOENT;
1159 #ifdef CONFIG_COMPAT
1160         if (compat)
1161                 xt_compat_unlock(AF_INET6);
1162 #endif
1163         return ret;
1164 }
1165
1166 static int
1167 get_entries(struct net *net, struct ip6t_get_entries __user *uptr,
1168             const int *len)
1169 {
1170         int ret;
1171         struct ip6t_get_entries get;
1172         struct xt_table *t;
1173
1174         if (*len < sizeof(get)) {
1175                 duprintf("get_entries: %u < %zu\n", *len, sizeof(get));
1176                 return -EINVAL;
1177         }
1178         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1179                 return -EFAULT;
1180         if (*len != sizeof(struct ip6t_get_entries) + get.size) {
1181                 duprintf("get_entries: %u != %zu\n",
1182                          *len, sizeof(get) + get.size);
1183                 return -EINVAL;
1184         }
1185         get.name[sizeof(get.name) - 1] = '\0';
1186
1187         t = xt_find_table_lock(net, AF_INET6, get.name);
1188         if (!IS_ERR_OR_NULL(t)) {
1189                 struct xt_table_info *private = t->private;
1190                 duprintf("t->private->number = %u\n", private->number);
1191                 if (get.size == private->size)
1192                         ret = copy_entries_to_user(private->size,
1193                                                    t, uptr->entrytable);
1194                 else {
1195                         duprintf("get_entries: I've got %u not %u!\n",
1196                                  private->size, get.size);
1197                         ret = -EAGAIN;
1198                 }
1199                 module_put(t->me);
1200                 xt_table_unlock(t);
1201         } else
1202                 ret = t ? PTR_ERR(t) : -ENOENT;
1203
1204         return ret;
1205 }
1206
1207 static int
1208 __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
1209              struct xt_table_info *newinfo, unsigned int num_counters,
1210              void __user *counters_ptr)
1211 {
1212         int ret;
1213         struct xt_table *t;
1214         struct xt_table_info *oldinfo;
1215         struct xt_counters *counters;
1216         struct ip6t_entry *iter;
1217
1218         ret = 0;
1219         counters = vzalloc(num_counters * sizeof(struct xt_counters));
1220         if (!counters) {
1221                 ret = -ENOMEM;
1222                 goto out;
1223         }
1224
1225         t = try_then_request_module(xt_find_table_lock(net, AF_INET6, name),
1226                                     "ip6table_%s", name);
1227         if (IS_ERR_OR_NULL(t)) {
1228                 ret = t ? PTR_ERR(t) : -ENOENT;
1229                 goto free_newinfo_counters_untrans;
1230         }
1231
1232         /* You lied! */
1233         if (valid_hooks != t->valid_hooks) {
1234                 duprintf("Valid hook crap: %08X vs %08X\n",
1235                          valid_hooks, t->valid_hooks);
1236                 ret = -EINVAL;
1237                 goto put_module;
1238         }
1239
1240         oldinfo = xt_replace_table(t, num_counters, newinfo, &ret);
1241         if (!oldinfo)
1242                 goto put_module;
1243
1244         /* Update module usage count based on number of rules */
1245         duprintf("do_replace: oldnum=%u, initnum=%u, newnum=%u\n",
1246                 oldinfo->number, oldinfo->initial_entries, newinfo->number);
1247         if ((oldinfo->number > oldinfo->initial_entries) ||
1248             (newinfo->number <= oldinfo->initial_entries))
1249                 module_put(t->me);
1250         if ((oldinfo->number > oldinfo->initial_entries) &&
1251             (newinfo->number <= oldinfo->initial_entries))
1252                 module_put(t->me);
1253
1254         /* Get the old counters, and synchronize with replace */
1255         get_counters(oldinfo, counters);
1256
1257         /* Decrease module usage counts and free resource */
1258         xt_entry_foreach(iter, oldinfo->entries, oldinfo->size)
1259                 cleanup_entry(iter, net);
1260
1261         xt_free_table_info(oldinfo);
1262         if (copy_to_user(counters_ptr, counters,
1263                          sizeof(struct xt_counters) * num_counters) != 0) {
1264                 /* Silent error, can't fail, new table is already in place */
1265                 net_warn_ratelimited("ip6tables: counters copy to user failed while replacing table\n");
1266         }
1267         vfree(counters);
1268         xt_table_unlock(t);
1269         return ret;
1270
1271  put_module:
1272         module_put(t->me);
1273         xt_table_unlock(t);
1274  free_newinfo_counters_untrans:
1275         vfree(counters);
1276  out:
1277         return ret;
1278 }
1279
1280 static int
1281 do_replace(struct net *net, const void __user *user, unsigned int len)
1282 {
1283         int ret;
1284         struct ip6t_replace tmp;
1285         struct xt_table_info *newinfo;
1286         void *loc_cpu_entry;
1287         struct ip6t_entry *iter;
1288
1289         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1290                 return -EFAULT;
1291
1292         /* overflow check */
1293         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1294                 return -ENOMEM;
1295         if (tmp.num_counters == 0)
1296                 return -EINVAL;
1297
1298         tmp.name[sizeof(tmp.name)-1] = 0;
1299
1300         newinfo = xt_alloc_table_info(tmp.size);
1301         if (!newinfo)
1302                 return -ENOMEM;
1303
1304         loc_cpu_entry = newinfo->entries;
1305         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1306                            tmp.size) != 0) {
1307                 ret = -EFAULT;
1308                 goto free_newinfo;
1309         }
1310
1311         ret = translate_table(net, newinfo, loc_cpu_entry, &tmp);
1312         if (ret != 0)
1313                 goto free_newinfo;
1314
1315         duprintf("ip_tables: Translated table\n");
1316
1317         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1318                            tmp.num_counters, tmp.counters);
1319         if (ret)
1320                 goto free_newinfo_untrans;
1321         return 0;
1322
1323  free_newinfo_untrans:
1324         xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1325                 cleanup_entry(iter, net);
1326  free_newinfo:
1327         xt_free_table_info(newinfo);
1328         return ret;
1329 }
1330
1331 static int
1332 do_add_counters(struct net *net, const void __user *user, unsigned int len,
1333                 int compat)
1334 {
1335         unsigned int i;
1336         struct xt_counters_info tmp;
1337         struct xt_counters *paddc;
1338         struct xt_table *t;
1339         const struct xt_table_info *private;
1340         int ret = 0;
1341         struct ip6t_entry *iter;
1342         unsigned int addend;
1343
1344         paddc = xt_copy_counters_from_user(user, len, &tmp, compat);
1345         if (IS_ERR(paddc))
1346                 return PTR_ERR(paddc);
1347         t = xt_find_table_lock(net, AF_INET6, tmp.name);
1348         if (IS_ERR_OR_NULL(t)) {
1349                 ret = t ? PTR_ERR(t) : -ENOENT;
1350                 goto free;
1351         }
1352
1353         local_bh_disable();
1354         private = t->private;
1355         if (private->number != tmp.num_counters) {
1356                 ret = -EINVAL;
1357                 goto unlock_up_free;
1358         }
1359
1360         i = 0;
1361         addend = xt_write_recseq_begin();
1362         xt_entry_foreach(iter, private->entries, private->size) {
1363                 struct xt_counters *tmp;
1364
1365                 tmp = xt_get_this_cpu_counter(&iter->counters);
1366                 ADD_COUNTER(*tmp, paddc[i].bcnt, paddc[i].pcnt);
1367                 ++i;
1368         }
1369         xt_write_recseq_end(addend);
1370  unlock_up_free:
1371         local_bh_enable();
1372         xt_table_unlock(t);
1373         module_put(t->me);
1374  free:
1375         vfree(paddc);
1376
1377         return ret;
1378 }
1379
1380 #ifdef CONFIG_COMPAT
1381 struct compat_ip6t_replace {
1382         char                    name[XT_TABLE_MAXNAMELEN];
1383         u32                     valid_hooks;
1384         u32                     num_entries;
1385         u32                     size;
1386         u32                     hook_entry[NF_INET_NUMHOOKS];
1387         u32                     underflow[NF_INET_NUMHOOKS];
1388         u32                     num_counters;
1389         compat_uptr_t           counters;       /* struct xt_counters * */
1390         struct compat_ip6t_entry entries[0];
1391 };
1392
1393 static int
1394 compat_copy_entry_to_user(struct ip6t_entry *e, void __user **dstptr,
1395                           unsigned int *size, struct xt_counters *counters,
1396                           unsigned int i)
1397 {
1398         struct xt_entry_target *t;
1399         struct compat_ip6t_entry __user *ce;
1400         u_int16_t target_offset, next_offset;
1401         compat_uint_t origsize;
1402         const struct xt_entry_match *ematch;
1403         int ret = 0;
1404
1405         origsize = *size;
1406         ce = (struct compat_ip6t_entry __user *)*dstptr;
1407         if (copy_to_user(ce, e, sizeof(struct ip6t_entry)) != 0 ||
1408             copy_to_user(&ce->counters, &counters[i],
1409             sizeof(counters[i])) != 0)
1410                 return -EFAULT;
1411
1412         *dstptr += sizeof(struct compat_ip6t_entry);
1413         *size -= sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1414
1415         xt_ematch_foreach(ematch, e) {
1416                 ret = xt_compat_match_to_user(ematch, dstptr, size);
1417                 if (ret != 0)
1418                         return ret;
1419         }
1420         target_offset = e->target_offset - (origsize - *size);
1421         t = ip6t_get_target(e);
1422         ret = xt_compat_target_to_user(t, dstptr, size);
1423         if (ret)
1424                 return ret;
1425         next_offset = e->next_offset - (origsize - *size);
1426         if (put_user(target_offset, &ce->target_offset) != 0 ||
1427             put_user(next_offset, &ce->next_offset) != 0)
1428                 return -EFAULT;
1429         return 0;
1430 }
1431
1432 static int
1433 compat_find_calc_match(struct xt_entry_match *m,
1434                        const struct ip6t_ip6 *ipv6,
1435                        int *size)
1436 {
1437         struct xt_match *match;
1438
1439         match = xt_request_find_match(NFPROTO_IPV6, m->u.user.name,
1440                                       m->u.user.revision);
1441         if (IS_ERR(match)) {
1442                 duprintf("compat_check_calc_match: `%s' not found\n",
1443                          m->u.user.name);
1444                 return PTR_ERR(match);
1445         }
1446         m->u.kernel.match = match;
1447         *size += xt_compat_match_offset(match);
1448         return 0;
1449 }
1450
1451 static void compat_release_entry(struct compat_ip6t_entry *e)
1452 {
1453         struct xt_entry_target *t;
1454         struct xt_entry_match *ematch;
1455
1456         /* Cleanup all matches */
1457         xt_ematch_foreach(ematch, e)
1458                 module_put(ematch->u.kernel.match->me);
1459         t = compat_ip6t_get_target(e);
1460         module_put(t->u.kernel.target->me);
1461 }
1462
1463 static int
1464 check_compat_entry_size_and_hooks(struct compat_ip6t_entry *e,
1465                                   struct xt_table_info *newinfo,
1466                                   unsigned int *size,
1467                                   const unsigned char *base,
1468                                   const unsigned char *limit)
1469 {
1470         struct xt_entry_match *ematch;
1471         struct xt_entry_target *t;
1472         struct xt_target *target;
1473         unsigned int entry_offset;
1474         unsigned int j;
1475         int ret, off;
1476
1477         duprintf("check_compat_entry_size_and_hooks %p\n", e);
1478         if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 ||
1479             (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit ||
1480             (unsigned char *)e + e->next_offset > limit) {
1481                 duprintf("Bad offset %p, limit = %p\n", e, limit);
1482                 return -EINVAL;
1483         }
1484
1485         if (e->next_offset < sizeof(struct compat_ip6t_entry) +
1486                              sizeof(struct compat_xt_entry_target)) {
1487                 duprintf("checking: element %p size %u\n",
1488                          e, e->next_offset);
1489                 return -EINVAL;
1490         }
1491
1492         if (!ip6_checkentry(&e->ipv6))
1493                 return -EINVAL;
1494
1495         ret = xt_compat_check_entry_offsets(e, e->elems,
1496                                             e->target_offset, e->next_offset);
1497         if (ret)
1498                 return ret;
1499
1500         off = sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1501         entry_offset = (void *)e - (void *)base;
1502         j = 0;
1503         xt_ematch_foreach(ematch, e) {
1504                 ret = compat_find_calc_match(ematch, &e->ipv6, &off);
1505                 if (ret != 0)
1506                         goto release_matches;
1507                 ++j;
1508         }
1509
1510         t = compat_ip6t_get_target(e);
1511         target = xt_request_find_target(NFPROTO_IPV6, t->u.user.name,
1512                                         t->u.user.revision);
1513         if (IS_ERR(target)) {
1514                 duprintf("check_compat_entry_size_and_hooks: `%s' not found\n",
1515                          t->u.user.name);
1516                 ret = PTR_ERR(target);
1517                 goto release_matches;
1518         }
1519         t->u.kernel.target = target;
1520
1521         off += xt_compat_target_offset(target);
1522         *size += off;
1523         ret = xt_compat_add_offset(AF_INET6, entry_offset, off);
1524         if (ret)
1525                 goto out;
1526
1527         return 0;
1528
1529 out:
1530         module_put(t->u.kernel.target->me);
1531 release_matches:
1532         xt_ematch_foreach(ematch, e) {
1533                 if (j-- == 0)
1534                         break;
1535                 module_put(ematch->u.kernel.match->me);
1536         }
1537         return ret;
1538 }
1539
1540 static void
1541 compat_copy_entry_from_user(struct compat_ip6t_entry *e, void **dstptr,
1542                             unsigned int *size,
1543                             struct xt_table_info *newinfo, unsigned char *base)
1544 {
1545         struct xt_entry_target *t;
1546         struct ip6t_entry *de;
1547         unsigned int origsize;
1548         int h;
1549         struct xt_entry_match *ematch;
1550
1551         origsize = *size;
1552         de = (struct ip6t_entry *)*dstptr;
1553         memcpy(de, e, sizeof(struct ip6t_entry));
1554         memcpy(&de->counters, &e->counters, sizeof(e->counters));
1555
1556         *dstptr += sizeof(struct ip6t_entry);
1557         *size += sizeof(struct ip6t_entry) - sizeof(struct compat_ip6t_entry);
1558
1559         xt_ematch_foreach(ematch, e)
1560                 xt_compat_match_from_user(ematch, dstptr, size);
1561
1562         de->target_offset = e->target_offset - (origsize - *size);
1563         t = compat_ip6t_get_target(e);
1564         xt_compat_target_from_user(t, dstptr, size);
1565
1566         de->next_offset = e->next_offset - (origsize - *size);
1567         for (h = 0; h < NF_INET_NUMHOOKS; h++) {
1568                 if ((unsigned char *)de - base < newinfo->hook_entry[h])
1569                         newinfo->hook_entry[h] -= origsize - *size;
1570                 if ((unsigned char *)de - base < newinfo->underflow[h])
1571                         newinfo->underflow[h] -= origsize - *size;
1572         }
1573 }
1574
1575 static int
1576 translate_compat_table(struct net *net,
1577                        struct xt_table_info **pinfo,
1578                        void **pentry0,
1579                        const struct compat_ip6t_replace *compatr)
1580 {
1581         unsigned int i, j;
1582         struct xt_table_info *newinfo, *info;
1583         void *pos, *entry0, *entry1;
1584         struct compat_ip6t_entry *iter0;
1585         struct ip6t_replace repl;
1586         unsigned int size;
1587         int ret = 0;
1588
1589         info = *pinfo;
1590         entry0 = *pentry0;
1591         size = compatr->size;
1592         info->number = compatr->num_entries;
1593
1594         duprintf("translate_compat_table: size %u\n", info->size);
1595         j = 0;
1596         xt_compat_lock(AF_INET6);
1597         xt_compat_init_offsets(AF_INET6, compatr->num_entries);
1598         /* Walk through entries, checking offsets. */
1599         xt_entry_foreach(iter0, entry0, compatr->size) {
1600                 ret = check_compat_entry_size_and_hooks(iter0, info, &size,
1601                                                         entry0,
1602                                                         entry0 + compatr->size);
1603                 if (ret != 0)
1604                         goto out_unlock;
1605                 ++j;
1606         }
1607
1608         ret = -EINVAL;
1609         if (j != compatr->num_entries) {
1610                 duprintf("translate_compat_table: %u not %u entries\n",
1611                          j, compatr->num_entries);
1612                 goto out_unlock;
1613         }
1614
1615         ret = -ENOMEM;
1616         newinfo = xt_alloc_table_info(size);
1617         if (!newinfo)
1618                 goto out_unlock;
1619
1620         memset(newinfo->entries, 0, size);
1621
1622         newinfo->number = compatr->num_entries;
1623         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1624                 newinfo->hook_entry[i] = compatr->hook_entry[i];
1625                 newinfo->underflow[i] = compatr->underflow[i];
1626         }
1627         entry1 = newinfo->entries;
1628         pos = entry1;
1629         size = compatr->size;
1630         xt_entry_foreach(iter0, entry0, compatr->size)
1631                 compat_copy_entry_from_user(iter0, &pos, &size,
1632                                             newinfo, entry1);
1633
1634         /* all module references in entry0 are now gone. */
1635         xt_compat_flush_offsets(AF_INET6);
1636         xt_compat_unlock(AF_INET6);
1637
1638         memcpy(&repl, compatr, sizeof(*compatr));
1639
1640         for (i = 0; i < NF_INET_NUMHOOKS; i++) {
1641                 repl.hook_entry[i] = newinfo->hook_entry[i];
1642                 repl.underflow[i] = newinfo->underflow[i];
1643         }
1644
1645         repl.num_counters = 0;
1646         repl.counters = NULL;
1647         repl.size = newinfo->size;
1648         ret = translate_table(net, newinfo, entry1, &repl);
1649         if (ret)
1650                 goto free_newinfo;
1651
1652         *pinfo = newinfo;
1653         *pentry0 = entry1;
1654         xt_free_table_info(info);
1655         return 0;
1656
1657 free_newinfo:
1658         xt_free_table_info(newinfo);
1659         return ret;
1660 out_unlock:
1661         xt_compat_flush_offsets(AF_INET6);
1662         xt_compat_unlock(AF_INET6);
1663         xt_entry_foreach(iter0, entry0, compatr->size) {
1664                 if (j-- == 0)
1665                         break;
1666                 compat_release_entry(iter0);
1667         }
1668         return ret;
1669 }
1670
1671 static int
1672 compat_do_replace(struct net *net, void __user *user, unsigned int len)
1673 {
1674         int ret;
1675         struct compat_ip6t_replace tmp;
1676         struct xt_table_info *newinfo;
1677         void *loc_cpu_entry;
1678         struct ip6t_entry *iter;
1679
1680         if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1681                 return -EFAULT;
1682
1683         /* overflow check */
1684         if (tmp.size >= INT_MAX / num_possible_cpus())
1685                 return -ENOMEM;
1686         if (tmp.num_counters >= INT_MAX / sizeof(struct xt_counters))
1687                 return -ENOMEM;
1688         if (tmp.num_counters == 0)
1689                 return -EINVAL;
1690
1691         tmp.name[sizeof(tmp.name)-1] = 0;
1692
1693         newinfo = xt_alloc_table_info(tmp.size);
1694         if (!newinfo)
1695                 return -ENOMEM;
1696
1697         loc_cpu_entry = newinfo->entries;
1698         if (copy_from_user(loc_cpu_entry, user + sizeof(tmp),
1699                            tmp.size) != 0) {
1700                 ret = -EFAULT;
1701                 goto free_newinfo;
1702         }
1703
1704         ret = translate_compat_table(net, &newinfo, &loc_cpu_entry, &tmp);
1705         if (ret != 0)
1706                 goto free_newinfo;
1707
1708         duprintf("compat_do_replace: Translated table\n");
1709
1710         ret = __do_replace(net, tmp.name, tmp.valid_hooks, newinfo,
1711                            tmp.num_counters, compat_ptr(tmp.counters));
1712         if (ret)
1713                 goto free_newinfo_untrans;
1714         return 0;
1715
1716  free_newinfo_untrans:
1717         xt_entry_foreach(iter, loc_cpu_entry, newinfo->size)
1718                 cleanup_entry(iter, net);
1719  free_newinfo:
1720         xt_free_table_info(newinfo);
1721         return ret;
1722 }
1723
1724 static int
1725 compat_do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user,
1726                        unsigned int len)
1727 {
1728         int ret;
1729
1730         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1731                 return -EPERM;
1732
1733         switch (cmd) {
1734         case IP6T_SO_SET_REPLACE:
1735                 ret = compat_do_replace(sock_net(sk), user, len);
1736                 break;
1737
1738         case IP6T_SO_SET_ADD_COUNTERS:
1739                 ret = do_add_counters(sock_net(sk), user, len, 1);
1740                 break;
1741
1742         default:
1743                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1744                 ret = -EINVAL;
1745         }
1746
1747         return ret;
1748 }
1749
1750 struct compat_ip6t_get_entries {
1751         char name[XT_TABLE_MAXNAMELEN];
1752         compat_uint_t size;
1753         struct compat_ip6t_entry entrytable[0];
1754 };
1755
1756 static int
1757 compat_copy_entries_to_user(unsigned int total_size, struct xt_table *table,
1758                             void __user *userptr)
1759 {
1760         struct xt_counters *counters;
1761         const struct xt_table_info *private = table->private;
1762         void __user *pos;
1763         unsigned int size;
1764         int ret = 0;
1765         unsigned int i = 0;
1766         struct ip6t_entry *iter;
1767
1768         counters = alloc_counters(table);
1769         if (IS_ERR(counters))
1770                 return PTR_ERR(counters);
1771
1772         pos = userptr;
1773         size = total_size;
1774         xt_entry_foreach(iter, private->entries, total_size) {
1775                 ret = compat_copy_entry_to_user(iter, &pos,
1776                                                 &size, counters, i++);
1777                 if (ret != 0)
1778                         break;
1779         }
1780
1781         vfree(counters);
1782         return ret;
1783 }
1784
1785 static int
1786 compat_get_entries(struct net *net, struct compat_ip6t_get_entries __user *uptr,
1787                    int *len)
1788 {
1789         int ret;
1790         struct compat_ip6t_get_entries get;
1791         struct xt_table *t;
1792
1793         if (*len < sizeof(get)) {
1794                 duprintf("compat_get_entries: %u < %zu\n", *len, sizeof(get));
1795                 return -EINVAL;
1796         }
1797
1798         if (copy_from_user(&get, uptr, sizeof(get)) != 0)
1799                 return -EFAULT;
1800
1801         if (*len != sizeof(struct compat_ip6t_get_entries) + get.size) {
1802                 duprintf("compat_get_entries: %u != %zu\n",
1803                          *len, sizeof(get) + get.size);
1804                 return -EINVAL;
1805         }
1806         get.name[sizeof(get.name) - 1] = '\0';
1807
1808         xt_compat_lock(AF_INET6);
1809         t = xt_find_table_lock(net, AF_INET6, get.name);
1810         if (!IS_ERR_OR_NULL(t)) {
1811                 const struct xt_table_info *private = t->private;
1812                 struct xt_table_info info;
1813                 duprintf("t->private->number = %u\n", private->number);
1814                 ret = compat_table_info(private, &info);
1815                 if (!ret && get.size == info.size) {
1816                         ret = compat_copy_entries_to_user(private->size,
1817                                                           t, uptr->entrytable);
1818                 } else if (!ret) {
1819                         duprintf("compat_get_entries: I've got %u not %u!\n",
1820                                  private->size, get.size);
1821                         ret = -EAGAIN;
1822                 }
1823                 xt_compat_flush_offsets(AF_INET6);
1824                 module_put(t->me);
1825                 xt_table_unlock(t);
1826         } else
1827                 ret = t ? PTR_ERR(t) : -ENOENT;
1828
1829         xt_compat_unlock(AF_INET6);
1830         return ret;
1831 }
1832
1833 static int do_ip6t_get_ctl(struct sock *, int, void __user *, int *);
1834
1835 static int
1836 compat_do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1837 {
1838         int ret;
1839
1840         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1841                 return -EPERM;
1842
1843         switch (cmd) {
1844         case IP6T_SO_GET_INFO:
1845                 ret = get_info(sock_net(sk), user, len, 1);
1846                 break;
1847         case IP6T_SO_GET_ENTRIES:
1848                 ret = compat_get_entries(sock_net(sk), user, len);
1849                 break;
1850         default:
1851                 ret = do_ip6t_get_ctl(sk, cmd, user, len);
1852         }
1853         return ret;
1854 }
1855 #endif
1856
1857 static int
1858 do_ip6t_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len)
1859 {
1860         int ret;
1861
1862         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1863                 return -EPERM;
1864
1865         switch (cmd) {
1866         case IP6T_SO_SET_REPLACE:
1867                 ret = do_replace(sock_net(sk), user, len);
1868                 break;
1869
1870         case IP6T_SO_SET_ADD_COUNTERS:
1871                 ret = do_add_counters(sock_net(sk), user, len, 0);
1872                 break;
1873
1874         default:
1875                 duprintf("do_ip6t_set_ctl:  unknown request %i\n", cmd);
1876                 ret = -EINVAL;
1877         }
1878
1879         return ret;
1880 }
1881
1882 static int
1883 do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1884 {
1885         int ret;
1886
1887         if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_ADMIN))
1888                 return -EPERM;
1889
1890         switch (cmd) {
1891         case IP6T_SO_GET_INFO:
1892                 ret = get_info(sock_net(sk), user, len, 0);
1893                 break;
1894
1895         case IP6T_SO_GET_ENTRIES:
1896                 ret = get_entries(sock_net(sk), user, len);
1897                 break;
1898
1899         case IP6T_SO_GET_REVISION_MATCH:
1900         case IP6T_SO_GET_REVISION_TARGET: {
1901                 struct xt_get_revision rev;
1902                 int target;
1903
1904                 if (*len != sizeof(rev)) {
1905                         ret = -EINVAL;
1906                         break;
1907                 }
1908                 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1909                         ret = -EFAULT;
1910                         break;
1911                 }
1912                 rev.name[sizeof(rev.name)-1] = 0;
1913
1914                 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1915                         target = 1;
1916                 else
1917                         target = 0;
1918
1919                 try_then_request_module(xt_find_revision(AF_INET6, rev.name,
1920                                                          rev.revision,
1921                                                          target, &ret),
1922                                         "ip6t_%s", rev.name);
1923                 break;
1924         }
1925
1926         default:
1927                 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1928                 ret = -EINVAL;
1929         }
1930
1931         return ret;
1932 }
1933
1934 struct xt_table *ip6t_register_table(struct net *net,
1935                                      const struct xt_table *table,
1936                                      const struct ip6t_replace *repl)
1937 {
1938         int ret;
1939         struct xt_table_info *newinfo;
1940         struct xt_table_info bootstrap = {0};
1941         void *loc_cpu_entry;
1942         struct xt_table *new_table;
1943
1944         newinfo = xt_alloc_table_info(repl->size);
1945         if (!newinfo) {
1946                 ret = -ENOMEM;
1947                 goto out;
1948         }
1949
1950         loc_cpu_entry = newinfo->entries;
1951         memcpy(loc_cpu_entry, repl->entries, repl->size);
1952
1953         ret = translate_table(net, newinfo, loc_cpu_entry, repl);
1954         if (ret != 0)
1955                 goto out_free;
1956
1957         new_table = xt_register_table(net, table, &bootstrap, newinfo);
1958         if (IS_ERR(new_table)) {
1959                 ret = PTR_ERR(new_table);
1960                 goto out_free;
1961         }
1962         return new_table;
1963
1964 out_free:
1965         xt_free_table_info(newinfo);
1966 out:
1967         return ERR_PTR(ret);
1968 }
1969
1970 void ip6t_unregister_table(struct net *net, struct xt_table *table)
1971 {
1972         struct xt_table_info *private;
1973         void *loc_cpu_entry;
1974         struct module *table_owner = table->me;
1975         struct ip6t_entry *iter;
1976
1977         private = xt_unregister_table(table);
1978
1979         /* Decrease module usage counts and free resources */
1980         loc_cpu_entry = private->entries;
1981         xt_entry_foreach(iter, loc_cpu_entry, private->size)
1982                 cleanup_entry(iter, net);
1983         if (private->number > private->initial_entries)
1984                 module_put(table_owner);
1985         xt_free_table_info(private);
1986 }
1987
1988 /* Returns 1 if the type and code is matched by the range, 0 otherwise */
1989 static inline bool
1990 icmp6_type_code_match(u_int8_t test_type, u_int8_t min_code, u_int8_t max_code,
1991                      u_int8_t type, u_int8_t code,
1992                      bool invert)
1993 {
1994         return (type == test_type && code >= min_code && code <= max_code)
1995                 ^ invert;
1996 }
1997
1998 static bool
1999 icmp6_match(const struct sk_buff *skb, struct xt_action_param *par)
2000 {
2001         const struct icmp6hdr *ic;
2002         struct icmp6hdr _icmph;
2003         const struct ip6t_icmp *icmpinfo = par->matchinfo;
2004
2005         /* Must not be a fragment. */
2006         if (par->fragoff != 0)
2007                 return false;
2008
2009         ic = skb_header_pointer(skb, par->thoff, sizeof(_icmph), &_icmph);
2010         if (ic == NULL) {
2011                 /* We've been asked to examine this packet, and we
2012                  * can't.  Hence, no choice but to drop.
2013                  */
2014                 duprintf("Dropping evil ICMP tinygram.\n");
2015                 par->hotdrop = true;
2016                 return false;
2017         }
2018
2019         return icmp6_type_code_match(icmpinfo->type,
2020                                      icmpinfo->code[0],
2021                                      icmpinfo->code[1],
2022                                      ic->icmp6_type, ic->icmp6_code,
2023                                      !!(icmpinfo->invflags&IP6T_ICMP_INV));
2024 }
2025
2026 /* Called when user tries to insert an entry of this type. */
2027 static int icmp6_checkentry(const struct xt_mtchk_param *par)
2028 {
2029         const struct ip6t_icmp *icmpinfo = par->matchinfo;
2030
2031         /* Must specify no unknown invflags */
2032         return (icmpinfo->invflags & ~IP6T_ICMP_INV) ? -EINVAL : 0;
2033 }
2034
2035 /* The built-in targets: standard (NULL) and error. */
2036 static struct xt_target ip6t_builtin_tg[] __read_mostly = {
2037         {
2038                 .name             = XT_STANDARD_TARGET,
2039                 .targetsize       = sizeof(int),
2040                 .family           = NFPROTO_IPV6,
2041 #ifdef CONFIG_COMPAT
2042                 .compatsize       = sizeof(compat_int_t),
2043                 .compat_from_user = compat_standard_from_user,
2044                 .compat_to_user   = compat_standard_to_user,
2045 #endif
2046         },
2047         {
2048                 .name             = XT_ERROR_TARGET,
2049                 .target           = ip6t_error,
2050                 .targetsize       = XT_FUNCTION_MAXNAMELEN,
2051                 .family           = NFPROTO_IPV6,
2052         },
2053 };
2054
2055 static struct nf_sockopt_ops ip6t_sockopts = {
2056         .pf             = PF_INET6,
2057         .set_optmin     = IP6T_BASE_CTL,
2058         .set_optmax     = IP6T_SO_SET_MAX+1,
2059         .set            = do_ip6t_set_ctl,
2060 #ifdef CONFIG_COMPAT
2061         .compat_set     = compat_do_ip6t_set_ctl,
2062 #endif
2063         .get_optmin     = IP6T_BASE_CTL,
2064         .get_optmax     = IP6T_SO_GET_MAX+1,
2065         .get            = do_ip6t_get_ctl,
2066 #ifdef CONFIG_COMPAT
2067         .compat_get     = compat_do_ip6t_get_ctl,
2068 #endif
2069         .owner          = THIS_MODULE,
2070 };
2071
2072 static struct xt_match ip6t_builtin_mt[] __read_mostly = {
2073         {
2074                 .name       = "icmp6",
2075                 .match      = icmp6_match,
2076                 .matchsize  = sizeof(struct ip6t_icmp),
2077                 .checkentry = icmp6_checkentry,
2078                 .proto      = IPPROTO_ICMPV6,
2079                 .family     = NFPROTO_IPV6,
2080                 .me         = THIS_MODULE,
2081         },
2082 };
2083
2084 static int __net_init ip6_tables_net_init(struct net *net)
2085 {
2086         return xt_proto_init(net, NFPROTO_IPV6);
2087 }
2088
2089 static void __net_exit ip6_tables_net_exit(struct net *net)
2090 {
2091         xt_proto_fini(net, NFPROTO_IPV6);
2092 }
2093
2094 static struct pernet_operations ip6_tables_net_ops = {
2095         .init = ip6_tables_net_init,
2096         .exit = ip6_tables_net_exit,
2097 };
2098
2099 static int __init ip6_tables_init(void)
2100 {
2101         int ret;
2102
2103         ret = register_pernet_subsys(&ip6_tables_net_ops);
2104         if (ret < 0)
2105                 goto err1;
2106
2107         /* No one else will be downing sem now, so we won't sleep */
2108         ret = xt_register_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2109         if (ret < 0)
2110                 goto err2;
2111         ret = xt_register_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2112         if (ret < 0)
2113                 goto err4;
2114
2115         /* Register setsockopt */
2116         ret = nf_register_sockopt(&ip6t_sockopts);
2117         if (ret < 0)
2118                 goto err5;
2119
2120         pr_info("(C) 2000-2006 Netfilter Core Team\n");
2121         return 0;
2122
2123 err5:
2124         xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2125 err4:
2126         xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2127 err2:
2128         unregister_pernet_subsys(&ip6_tables_net_ops);
2129 err1:
2130         return ret;
2131 }
2132
2133 static void __exit ip6_tables_fini(void)
2134 {
2135         nf_unregister_sockopt(&ip6t_sockopts);
2136
2137         xt_unregister_matches(ip6t_builtin_mt, ARRAY_SIZE(ip6t_builtin_mt));
2138         xt_unregister_targets(ip6t_builtin_tg, ARRAY_SIZE(ip6t_builtin_tg));
2139         unregister_pernet_subsys(&ip6_tables_net_ops);
2140 }
2141
2142 EXPORT_SYMBOL(ip6t_register_table);
2143 EXPORT_SYMBOL(ip6t_unregister_table);
2144 EXPORT_SYMBOL(ip6t_do_table);
2145
2146 module_init(ip6_tables_init);
2147 module_exit(ip6_tables_fini);