aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorHarald Welte <laforge@netfilter.org>2005-10-26 03:34:24 -0400
committerArnaldo Carvalho de Melo <acme@mandriva.com>2005-10-31 13:36:08 -0500
commit6b7d31fcdda5938e5d3f1f8b0922cc25aa200dfc (patch)
treec44f46d7eab0ea138247018ba1e04da6df8ae9d4 /net/ipv6
parent6ede2463c8d7ea949f8e7ef35243490c415ddc2f (diff)
[NETFILTER]: Add "revision" support to arp_tables and ip6_tables
Like ip_tables already has it for some time, this adds support for having multiple revisions for each match/target. We steal one byte from the name in order to accomodate a 8 bit version number. Signed-off-by: Harald Welte <laforge@netfilter.org> Signed-off-by: Arnaldo Carvalho de Melo <acme@mandriva.com>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/netfilter/ip6_tables.c298
-rw-r--r--net/ipv6/netfilter/ip6t_MARK.c8
2 files changed, 192 insertions, 114 deletions
diff --git a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
index 21deec25a12b..7d492226c16e 100644
--- a/net/ipv6/netfilter/ip6_tables.c
+++ b/net/ipv6/netfilter/ip6_tables.c
@@ -2,7 +2,7 @@
2 * Packet matching code. 2 * Packet matching code.
3 * 3 *
4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling 4 * Copyright (C) 1999 Paul `Rusty' Russell & Michael J. Neuling
5 * Copyright (C) 2000-2002 Netfilter core team <coreteam@netfilter.org> 5 * Copyright (C) 2000-2005 Netfilter Core Team <coreteam@netfilter.org>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 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 8 * it under the terms of the GNU General Public License version 2 as
@@ -23,7 +23,6 @@
23#include <linux/tcp.h> 23#include <linux/tcp.h>
24#include <linux/udp.h> 24#include <linux/udp.h>
25#include <linux/icmpv6.h> 25#include <linux/icmpv6.h>
26#include <net/ip.h>
27#include <net/ipv6.h> 26#include <net/ipv6.h>
28#include <asm/uaccess.h> 27#include <asm/uaccess.h>
29#include <asm/semaphore.h> 28#include <asm/semaphore.h>
@@ -80,13 +79,12 @@ static DECLARE_MUTEX(ip6t_mutex);
80#define inline 79#define inline
81#endif 80#endif
82 81
83/* Locking is simple: we assume at worst case there will be one packet 82/*
84 in user context and one from bottom halves (or soft irq if Alexey's
85 softnet patch was applied).
86
87 We keep a set of rules for each CPU, so we can avoid write-locking 83 We keep a set of rules for each CPU, so we can avoid write-locking
88 them; doing a readlock_bh() stops packets coming through if we're 84 them in the softirq when updating the counters and therefore
89 in user context. 85 only need to read-lock in the softirq; doing a write_lock_bh() in user
86 context stops packets coming through and allows user context to read
87 the counters or update the rules.
90 88
91 To be cache friendly on SMP, we arrange them like so: 89 To be cache friendly on SMP, we arrange them like so:
92 [ n-entries ] 90 [ n-entries ]
@@ -356,7 +354,7 @@ ip6t_do_table(struct sk_buff **pskb,
356 struct ip6t_table *table, 354 struct ip6t_table *table,
357 void *userdata) 355 void *userdata)
358{ 356{
359 static const char nulldevname[IFNAMSIZ]; 357 static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
360 int offset = 0; 358 int offset = 0;
361 unsigned int protoff = 0; 359 unsigned int protoff = 0;
362 int hotdrop = 0; 360 int hotdrop = 0;
@@ -369,7 +367,6 @@ ip6t_do_table(struct sk_buff **pskb,
369 /* Initialization */ 367 /* Initialization */
370 indev = in ? in->name : nulldevname; 368 indev = in ? in->name : nulldevname;
371 outdev = out ? out->name : nulldevname; 369 outdev = out ? out->name : nulldevname;
372
373 /* We handle fragments by dealing with the first fragment as 370 /* We handle fragments by dealing with the first fragment as
374 * if it was a normal packet. All other fragments are treated 371 * if it was a normal packet. All other fragments are treated
375 * normally, except that they will NEVER match rules that ask 372 * normally, except that they will NEVER match rules that ask
@@ -497,75 +494,145 @@ ip6t_do_table(struct sk_buff **pskb,
497#endif 494#endif
498} 495}
499 496
500/* If it succeeds, returns element and locks mutex */ 497/*
501static inline void * 498 * These are weird, but module loading must not be done with mutex
502find_inlist_lock_noload(struct list_head *head, 499 * held (since they will register), and we have to have a single
503 const char *name, 500 * function to use try_then_request_module().
504 int *error, 501 */
505 struct semaphore *mutex) 502
503/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
504static inline struct ip6t_table *find_table_lock(const char *name)
506{ 505{
507 void *ret; 506 struct ip6t_table *t;
508 507
509#if 1 508 if (down_interruptible(&ip6t_mutex) != 0)
510 duprintf("find_inlist: searching for `%s' in %s.\n", 509 return ERR_PTR(-EINTR);
511 name, head == &ip6t_target ? "ip6t_target"
512 : head == &ip6t_match ? "ip6t_match"
513 : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN");
514#endif
515 510
516 *error = down_interruptible(mutex); 511 list_for_each_entry(t, &ip6t_tables, list)
517 if (*error != 0) 512 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
518 return NULL; 513 return t;
514 up(&ip6t_mutex);
515 return NULL;
516}
517
518/* Find match, grabs ref. Returns ERR_PTR() on error. */
519static inline struct ip6t_match *find_match(const char *name, u8 revision)
520{
521 struct ip6t_match *m;
522 int err = 0;
519 523
520 ret = list_named_find(head, name); 524 if (down_interruptible(&ip6t_mutex) != 0)
521 if (!ret) { 525 return ERR_PTR(-EINTR);
522 *error = -ENOENT; 526
523 up(mutex); 527 list_for_each_entry(m, &ip6t_match, list) {
528 if (strcmp(m->name, name) == 0) {
529 if (m->revision == revision) {
530 if (try_module_get(m->me)) {
531 up(&ip6t_mutex);
532 return m;
533 }
534 } else
535 err = -EPROTOTYPE; /* Found something. */
536 }
524 } 537 }
525 return ret; 538 up(&ip6t_mutex);
539 return ERR_PTR(err);
526} 540}
527 541
528#ifndef CONFIG_KMOD 542/* Find target, grabs ref. Returns ERR_PTR() on error. */
529#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) 543static inline struct ip6t_target *find_target(const char *name, u8 revision)
530#else
531static void *
532find_inlist_lock(struct list_head *head,
533 const char *name,
534 const char *prefix,
535 int *error,
536 struct semaphore *mutex)
537{ 544{
538 void *ret; 545 struct ip6t_target *t;
546 int err = 0;
539 547
540 ret = find_inlist_lock_noload(head, name, error, mutex); 548 if (down_interruptible(&ip6t_mutex) != 0)
541 if (!ret) { 549 return ERR_PTR(-EINTR);
542 duprintf("find_inlist: loading `%s%s'.\n", prefix, name); 550
543 request_module("%s%s", prefix, name); 551 list_for_each_entry(t, &ip6t_target, list) {
544 ret = find_inlist_lock_noload(head, name, error, mutex); 552 if (strcmp(t->name, name) == 0) {
553 if (t->revision == revision) {
554 if (try_module_get(t->me)) {
555 up(&ip6t_mutex);
556 return t;
557 }
558 } else
559 err = -EPROTOTYPE; /* Found something. */
560 }
545 } 561 }
562 up(&ip6t_mutex);
563 return ERR_PTR(err);
564}
546 565
547 return ret; 566struct ip6t_target *ip6t_find_target(const char *name, u8 revision)
567{
568 struct ip6t_target *target;
569
570 target = try_then_request_module(find_target(name, revision),
571 "ip6t_%s", name);
572 if (IS_ERR(target) || !target)
573 return NULL;
574 return target;
548} 575}
549#endif
550 576
551static inline struct ip6t_table * 577static int match_revfn(const char *name, u8 revision, int *bestp)
552ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex)
553{ 578{
554 return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex); 579 struct ip6t_match *m;
580 int have_rev = 0;
581
582 list_for_each_entry(m, &ip6t_match, list) {
583 if (strcmp(m->name, name) == 0) {
584 if (m->revision > *bestp)
585 *bestp = m->revision;
586 if (m->revision == revision)
587 have_rev = 1;
588 }
589 }
590 return have_rev;
555} 591}
556 592
557static inline struct ip6t_match * 593static int target_revfn(const char *name, u8 revision, int *bestp)
558find_match_lock(const char *name, int *error, struct semaphore *mutex)
559{ 594{
560 return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex); 595 struct ip6t_target *t;
596 int have_rev = 0;
597
598 list_for_each_entry(t, &ip6t_target, list) {
599 if (strcmp(t->name, name) == 0) {
600 if (t->revision > *bestp)
601 *bestp = t->revision;
602 if (t->revision == revision)
603 have_rev = 1;
604 }
605 }
606 return have_rev;
561} 607}
562 608
563static struct ip6t_target * 609/* Returns true or fals (if no such extension at all) */
564ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex) 610static inline int find_revision(const char *name, u8 revision,
611 int (*revfn)(const char *, u8, int *),
612 int *err)
565{ 613{
566 return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex); 614 int have_rev, best = -1;
615
616 if (down_interruptible(&ip6t_mutex) != 0) {
617 *err = -EINTR;
618 return 1;
619 }
620 have_rev = revfn(name, revision, &best);
621 up(&ip6t_mutex);
622
623 /* Nothing at all? Return 0 to try loading module. */
624 if (best == -1) {
625 *err = -ENOENT;
626 return 0;
627 }
628
629 *err = best;
630 if (!have_rev)
631 *err = -EPROTONOSUPPORT;
632 return 1;
567} 633}
568 634
635
569/* All zeroes == unconditional rule. */ 636/* All zeroes == unconditional rule. */
570static inline int 637static inline int
571unconditional(const struct ip6t_ip6 *ipv6) 638unconditional(const struct ip6t_ip6 *ipv6)
@@ -725,20 +792,16 @@ check_match(struct ip6t_entry_match *m,
725 unsigned int hookmask, 792 unsigned int hookmask,
726 unsigned int *i) 793 unsigned int *i)
727{ 794{
728 int ret;
729 struct ip6t_match *match; 795 struct ip6t_match *match;
730 796
731 match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex); 797 match = try_then_request_module(find_match(m->u.user.name,
732 if (!match) { 798 m->u.user.revision),
733 // duprintf("check_match: `%s' not found\n", m->u.name); 799 "ip6t_%s", m->u.user.name);
734 return ret; 800 if (IS_ERR(match) || !match) {
735 } 801 duprintf("check_match: `%s' not found\n", m->u.user.name);
736 if (!try_module_get(match->me)) { 802 return match ? PTR_ERR(match) : -ENOENT;
737 up(&ip6t_mutex);
738 return -ENOENT;
739 } 803 }
740 m->u.kernel.match = match; 804 m->u.kernel.match = match;
741 up(&ip6t_mutex);
742 805
743 if (m->u.kernel.match->checkentry 806 if (m->u.kernel.match->checkentry
744 && !m->u.kernel.match->checkentry(name, ipv6, m->data, 807 && !m->u.kernel.match->checkentry(name, ipv6, m->data,
@@ -776,22 +839,16 @@ check_entry(struct ip6t_entry *e, const char *name, unsigned int size,
776 goto cleanup_matches; 839 goto cleanup_matches;
777 840
778 t = ip6t_get_target(e); 841 t = ip6t_get_target(e);
779 target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex); 842 target = try_then_request_module(find_target(t->u.user.name,
780 if (!target) { 843 t->u.user.revision),
844 "ip6t_%s", t->u.user.name);
845 if (IS_ERR(target) || !target) {
781 duprintf("check_entry: `%s' not found\n", t->u.user.name); 846 duprintf("check_entry: `%s' not found\n", t->u.user.name);
782 goto cleanup_matches; 847 ret = target ? PTR_ERR(target) : -ENOENT;
783 }
784 if (!try_module_get(target->me)) {
785 up(&ip6t_mutex);
786 ret = -ENOENT;
787 goto cleanup_matches; 848 goto cleanup_matches;
788 } 849 }
789 t->u.kernel.target = target; 850 t->u.kernel.target = target;
790 up(&ip6t_mutex); 851
791 if (!t->u.kernel.target) {
792 ret = -EBUSY;
793 goto cleanup_matches;
794 }
795 if (t->u.kernel.target == &ip6t_standard_target) { 852 if (t->u.kernel.target == &ip6t_standard_target) {
796 if (!standard_check(t, size)) { 853 if (!standard_check(t, size)) {
797 ret = -EINVAL; 854 ret = -EINVAL;
@@ -1118,8 +1175,8 @@ get_entries(const struct ip6t_get_entries *entries,
1118 int ret; 1175 int ret;
1119 struct ip6t_table *t; 1176 struct ip6t_table *t;
1120 1177
1121 t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex); 1178 t = find_table_lock(entries->name);
1122 if (t) { 1179 if (t && !IS_ERR(t)) {
1123 duprintf("t->private->number = %u\n", 1180 duprintf("t->private->number = %u\n",
1124 t->private->number); 1181 t->private->number);
1125 if (entries->size == t->private->size) 1182 if (entries->size == t->private->size)
@@ -1131,10 +1188,10 @@ get_entries(const struct ip6t_get_entries *entries,
1131 entries->size); 1188 entries->size);
1132 ret = -EINVAL; 1189 ret = -EINVAL;
1133 } 1190 }
1191 module_put(t->me);
1134 up(&ip6t_mutex); 1192 up(&ip6t_mutex);
1135 } else 1193 } else
1136 duprintf("get_entries: Can't find %s!\n", 1194 ret = t ? PTR_ERR(t) : -ENOENT;
1137 entries->name);
1138 1195
1139 return ret; 1196 return ret;
1140} 1197}
@@ -1182,22 +1239,19 @@ do_replace(void __user *user, unsigned int len)
1182 1239
1183 duprintf("ip_tables: Translated table\n"); 1240 duprintf("ip_tables: Translated table\n");
1184 1241
1185 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex); 1242 t = try_then_request_module(find_table_lock(tmp.name),
1186 if (!t) 1243 "ip6table_%s", tmp.name);
1244 if (!t || IS_ERR(t)) {
1245 ret = t ? PTR_ERR(t) : -ENOENT;
1187 goto free_newinfo_counters_untrans; 1246 goto free_newinfo_counters_untrans;
1247 }
1188 1248
1189 /* You lied! */ 1249 /* You lied! */
1190 if (tmp.valid_hooks != t->valid_hooks) { 1250 if (tmp.valid_hooks != t->valid_hooks) {
1191 duprintf("Valid hook crap: %08X vs %08X\n", 1251 duprintf("Valid hook crap: %08X vs %08X\n",
1192 tmp.valid_hooks, t->valid_hooks); 1252 tmp.valid_hooks, t->valid_hooks);
1193 ret = -EINVAL; 1253 ret = -EINVAL;
1194 goto free_newinfo_counters_untrans_unlock; 1254 goto put_module;
1195 }
1196
1197 /* Get a reference in advance, we're not allowed fail later */
1198 if (!try_module_get(t->me)) {
1199 ret = -EBUSY;
1200 goto free_newinfo_counters_untrans_unlock;
1201 } 1255 }
1202 1256
1203 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); 1257 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
@@ -1219,7 +1273,6 @@ do_replace(void __user *user, unsigned int len)
1219 /* Decrease module usage counts and free resource */ 1273 /* Decrease module usage counts and free resource */
1220 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL); 1274 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL);
1221 vfree(oldinfo); 1275 vfree(oldinfo);
1222 /* Silent error: too late now. */
1223 if (copy_to_user(tmp.counters, counters, 1276 if (copy_to_user(tmp.counters, counters,
1224 sizeof(struct ip6t_counters) * tmp.num_counters) != 0) 1277 sizeof(struct ip6t_counters) * tmp.num_counters) != 0)
1225 ret = -EFAULT; 1278 ret = -EFAULT;
@@ -1229,7 +1282,6 @@ do_replace(void __user *user, unsigned int len)
1229 1282
1230 put_module: 1283 put_module:
1231 module_put(t->me); 1284 module_put(t->me);
1232 free_newinfo_counters_untrans_unlock:
1233 up(&ip6t_mutex); 1285 up(&ip6t_mutex);
1234 free_newinfo_counters_untrans: 1286 free_newinfo_counters_untrans:
1235 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL); 1287 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL);
@@ -1268,7 +1320,7 @@ do_add_counters(void __user *user, unsigned int len)
1268 unsigned int i; 1320 unsigned int i;
1269 struct ip6t_counters_info tmp, *paddc; 1321 struct ip6t_counters_info tmp, *paddc;
1270 struct ip6t_table *t; 1322 struct ip6t_table *t;
1271 int ret; 1323 int ret = 0;
1272 1324
1273 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) 1325 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
1274 return -EFAULT; 1326 return -EFAULT;
@@ -1285,9 +1337,11 @@ do_add_counters(void __user *user, unsigned int len)
1285 goto free; 1337 goto free;
1286 } 1338 }
1287 1339
1288 t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex); 1340 t = find_table_lock(tmp.name);
1289 if (!t) 1341 if (!t || IS_ERR(t)) {
1342 ret = t ? PTR_ERR(t) : -ENOENT;
1290 goto free; 1343 goto free;
1344 }
1291 1345
1292 write_lock_bh(&t->lock); 1346 write_lock_bh(&t->lock);
1293 if (t->private->number != paddc->num_counters) { 1347 if (t->private->number != paddc->num_counters) {
@@ -1304,6 +1358,7 @@ do_add_counters(void __user *user, unsigned int len)
1304 unlock_up_free: 1358 unlock_up_free:
1305 write_unlock_bh(&t->lock); 1359 write_unlock_bh(&t->lock);
1306 up(&ip6t_mutex); 1360 up(&ip6t_mutex);
1361 module_put(t->me);
1307 free: 1362 free:
1308 vfree(paddc); 1363 vfree(paddc);
1309 1364
@@ -1360,8 +1415,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1360 break; 1415 break;
1361 } 1416 }
1362 name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; 1417 name[IP6T_TABLE_MAXNAMELEN-1] = '\0';
1363 t = ip6t_find_table_lock(name, &ret, &ip6t_mutex); 1418
1364 if (t) { 1419 t = try_then_request_module(find_table_lock(name),
1420 "ip6table_%s", name);
1421 if (t && !IS_ERR(t)) {
1365 struct ip6t_getinfo info; 1422 struct ip6t_getinfo info;
1366 1423
1367 info.valid_hooks = t->valid_hooks; 1424 info.valid_hooks = t->valid_hooks;
@@ -1377,9 +1434,10 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1377 ret = -EFAULT; 1434 ret = -EFAULT;
1378 else 1435 else
1379 ret = 0; 1436 ret = 0;
1380
1381 up(&ip6t_mutex); 1437 up(&ip6t_mutex);
1382 } 1438 module_put(t->me);
1439 } else
1440 ret = t ? PTR_ERR(t) : -ENOENT;
1383 } 1441 }
1384 break; 1442 break;
1385 1443
@@ -1400,6 +1458,31 @@ do_ip6t_get_ctl(struct sock *sk, int cmd, void __user *user, int *len)
1400 break; 1458 break;
1401 } 1459 }
1402 1460
1461 case IP6T_SO_GET_REVISION_MATCH:
1462 case IP6T_SO_GET_REVISION_TARGET: {
1463 struct ip6t_get_revision rev;
1464 int (*revfn)(const char *, u8, int *);
1465
1466 if (*len != sizeof(rev)) {
1467 ret = -EINVAL;
1468 break;
1469 }
1470 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1471 ret = -EFAULT;
1472 break;
1473 }
1474
1475 if (cmd == IP6T_SO_GET_REVISION_TARGET)
1476 revfn = target_revfn;
1477 else
1478 revfn = match_revfn;
1479
1480 try_then_request_module(find_revision(rev.name, rev.revision,
1481 revfn, &ret),
1482 "ip6t_%s", rev.name);
1483 break;
1484 }
1485
1403 default: 1486 default:
1404 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd); 1487 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd);
1405 ret = -EINVAL; 1488 ret = -EINVAL;
@@ -1417,12 +1500,7 @@ ip6t_register_target(struct ip6t_target *target)
1417 ret = down_interruptible(&ip6t_mutex); 1500 ret = down_interruptible(&ip6t_mutex);
1418 if (ret != 0) 1501 if (ret != 0)
1419 return ret; 1502 return ret;
1420 1503 list_add(&target->list, &ip6t_target);
1421 if (!list_named_insert(&ip6t_target, target)) {
1422 duprintf("ip6t_register_target: `%s' already in list!\n",
1423 target->name);
1424 ret = -EINVAL;
1425 }
1426 up(&ip6t_mutex); 1504 up(&ip6t_mutex);
1427 return ret; 1505 return ret;
1428} 1506}
@@ -1444,11 +1522,7 @@ ip6t_register_match(struct ip6t_match *match)
1444 if (ret != 0) 1522 if (ret != 0)
1445 return ret; 1523 return ret;
1446 1524
1447 if (!list_named_insert(&ip6t_match, match)) { 1525 list_add(&match->list, &ip6t_match);
1448 duprintf("ip6t_register_match: `%s' already in list!\n",
1449 match->name);
1450 ret = -EINVAL;
1451 }
1452 up(&ip6t_mutex); 1526 up(&ip6t_mutex);
1453 1527
1454 return ret; 1528 return ret;
diff --git a/net/ipv6/netfilter/ip6t_MARK.c b/net/ipv6/netfilter/ip6t_MARK.c
index 81924fcc5857..0c7584f92172 100644
--- a/net/ipv6/netfilter/ip6t_MARK.c
+++ b/net/ipv6/netfilter/ip6t_MARK.c
@@ -56,8 +56,12 @@ checkentry(const char *tablename,
56 return 1; 56 return 1;
57} 57}
58 58
59static struct ip6t_target ip6t_mark_reg 59static struct ip6t_target ip6t_mark_reg = {
60= { { NULL, NULL }, "MARK", target, checkentry, NULL, THIS_MODULE }; 60 .name = "MARK",
61 .target = target,
62 .checkentry = checkentry,
63 .me = THIS_MODULE
64};
61 65
62static int __init init(void) 66static int __init init(void)
63{ 67{