aboutsummaryrefslogtreecommitdiffstats
path: root/net
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
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')
-rw-r--r--net/ipv4/netfilter/arp_tables.c201
-rw-r--r--net/ipv6/netfilter/ip6_tables.c298
-rw-r--r--net/ipv6/netfilter/ip6t_MARK.c8
3 files changed, 323 insertions, 184 deletions
diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
index a7969286e6e7..3c2e9639bba6 100644
--- a/net/ipv4/netfilter/arp_tables.c
+++ b/net/ipv4/netfilter/arp_tables.c
@@ -347,58 +347,106 @@ unsigned int arpt_do_table(struct sk_buff **pskb,
347 return verdict; 347 return verdict;
348} 348}
349 349
350static inline void *find_inlist_lock_noload(struct list_head *head, 350/*
351 const char *name, 351 * These are weird, but module loading must not be done with mutex
352 int *error, 352 * held (since they will register), and we have to have a single
353 struct semaphore *mutex) 353 * function to use try_then_request_module().
354 */
355
356/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
357static inline struct arpt_table *find_table_lock(const char *name)
354{ 358{
355 void *ret; 359 struct arpt_table *t;
356 360
357 *error = down_interruptible(mutex); 361 if (down_interruptible(&arpt_mutex) != 0)
358 if (*error != 0) 362 return ERR_PTR(-EINTR);
359 return NULL;
360 363
361 ret = list_named_find(head, name); 364 list_for_each_entry(t, &arpt_tables, list)
362 if (!ret) { 365 if (strcmp(t->name, name) == 0 && try_module_get(t->me))
363 *error = -ENOENT; 366 return t;
364 up(mutex); 367 up(&arpt_mutex);
365 } 368 return NULL;
366 return ret;
367} 369}
368 370
369#ifndef CONFIG_KMOD 371
370#define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) 372/* Find target, grabs ref. Returns ERR_PTR() on error. */
371#else 373static inline struct arpt_target *find_target(const char *name, u8 revision)
372static void *
373find_inlist_lock(struct list_head *head,
374 const char *name,
375 const char *prefix,
376 int *error,
377 struct semaphore *mutex)
378{ 374{
379 void *ret; 375 struct arpt_target *t;
376 int err = 0;
380 377
381 ret = find_inlist_lock_noload(head, name, error, mutex); 378 if (down_interruptible(&arpt_mutex) != 0)
382 if (!ret) { 379 return ERR_PTR(-EINTR);
383 duprintf("find_inlist: loading `%s%s'.\n", prefix, name); 380
384 request_module("%s%s", prefix, name); 381 list_for_each_entry(t, &arpt_target, list) {
385 ret = find_inlist_lock_noload(head, name, error, mutex); 382 if (strcmp(t->name, name) == 0) {
383 if (t->revision == revision) {
384 if (try_module_get(t->me)) {
385 up(&arpt_mutex);
386 return t;
387 }
388 } else
389 err = -EPROTOTYPE; /* Found something. */
390 }
386 } 391 }
392 up(&arpt_mutex);
393 return ERR_PTR(err);
394}
387 395
388 return ret; 396struct arpt_target *arpt_find_target(const char *name, u8 revision)
397{
398 struct arpt_target *target;
399
400 target = try_then_request_module(find_target(name, revision),
401 "arpt_%s", name);
402 if (IS_ERR(target) || !target)
403 return NULL;
404 return target;
389} 405}
390#endif
391 406
392static inline struct arpt_table *arpt_find_table_lock(const char *name, int *error, struct semaphore *mutex) 407static int target_revfn(const char *name, u8 revision, int *bestp)
393{ 408{
394 return find_inlist_lock(&arpt_tables, name, "arptable_", error, mutex); 409 struct arpt_target *t;
410 int have_rev = 0;
411
412 list_for_each_entry(t, &arpt_target, list) {
413 if (strcmp(t->name, name) == 0) {
414 if (t->revision > *bestp)
415 *bestp = t->revision;
416 if (t->revision == revision)
417 have_rev =1;
418 }
419 }
420 return have_rev;
395} 421}
396 422
397static struct arpt_target *arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex) 423/* Returns true or false (if no such extension at all) */
424static inline int find_revision(const char *name, u8 revision,
425 int (*revfn)(const char *, u8, int *),
426 int *err)
398{ 427{
399 return find_inlist_lock(&arpt_target, name, "arpt_", error, mutex); 428 int have_rev, best = -1;
429
430 if (down_interruptible(&arpt_mutex) != 0) {
431 *err = -EINTR;
432 return 1;
433 }
434 have_rev = revfn(name, revision, &best);
435 up(&arpt_mutex);
436
437 /* Nothing at all? Return 0 to try loading module. */
438 if (best == -1) {
439 *err = -ENOENT;
440 return 0;
441 }
442
443 *err = best;
444 if (!have_rev)
445 *err = -EPROTONOSUPPORT;
446 return 1;
400} 447}
401 448
449
402/* All zeroes == unconditional rule. */ 450/* All zeroes == unconditional rule. */
403static inline int unconditional(const struct arpt_arp *arp) 451static inline int unconditional(const struct arpt_arp *arp)
404{ 452{
@@ -544,17 +592,15 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
544 } 592 }
545 593
546 t = arpt_get_target(e); 594 t = arpt_get_target(e);
547 target = arpt_find_target_lock(t->u.user.name, &ret, &arpt_mutex); 595 target = try_then_request_module(find_target(t->u.user.name,
548 if (!target) { 596 t->u.user.revision),
597 "arpt_%s", t->u.user.name);
598 if (IS_ERR(target) || !target) {
549 duprintf("check_entry: `%s' not found\n", t->u.user.name); 599 duprintf("check_entry: `%s' not found\n", t->u.user.name);
600 ret = target ? PTR_ERR(target) : -ENOENT;
550 goto out; 601 goto out;
551 } 602 }
552 if (!try_module_get((target->me))) {
553 ret = -ENOENT;
554 goto out_unlock;
555 }
556 t->u.kernel.target = target; 603 t->u.kernel.target = target;
557 up(&arpt_mutex);
558 604
559 if (t->u.kernel.target == &arpt_standard_target) { 605 if (t->u.kernel.target == &arpt_standard_target) {
560 if (!standard_check(t, size)) { 606 if (!standard_check(t, size)) {
@@ -576,8 +622,6 @@ static inline int check_entry(struct arpt_entry *e, const char *name, unsigned i
576 (*i)++; 622 (*i)++;
577 return 0; 623 return 0;
578 624
579out_unlock:
580 up(&arpt_mutex);
581out: 625out:
582 return ret; 626 return ret;
583} 627}
@@ -846,8 +890,8 @@ static int get_entries(const struct arpt_get_entries *entries,
846 int ret; 890 int ret;
847 struct arpt_table *t; 891 struct arpt_table *t;
848 892
849 t = arpt_find_table_lock(entries->name, &ret, &arpt_mutex); 893 t = find_table_lock(entries->name);
850 if (t) { 894 if (t || !IS_ERR(t)) {
851 duprintf("t->private->number = %u\n", 895 duprintf("t->private->number = %u\n",
852 t->private->number); 896 t->private->number);
853 if (entries->size == t->private->size) 897 if (entries->size == t->private->size)
@@ -859,10 +903,10 @@ static int get_entries(const struct arpt_get_entries *entries,
859 entries->size); 903 entries->size);
860 ret = -EINVAL; 904 ret = -EINVAL;
861 } 905 }
906 module_put(t->me);
862 up(&arpt_mutex); 907 up(&arpt_mutex);
863 } else 908 } else
864 duprintf("get_entries: Can't find %s!\n", 909 ret = t ? PTR_ERR(t) : -ENOENT;
865 entries->name);
866 910
867 return ret; 911 return ret;
868} 912}
@@ -913,22 +957,19 @@ static int do_replace(void __user *user, unsigned int len)
913 957
914 duprintf("arp_tables: Translated table\n"); 958 duprintf("arp_tables: Translated table\n");
915 959
916 t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex); 960 t = try_then_request_module(find_table_lock(tmp.name),
917 if (!t) 961 "arptable_%s", tmp.name);
962 if (!t || IS_ERR(t)) {
963 ret = t ? PTR_ERR(t) : -ENOENT;
918 goto free_newinfo_counters_untrans; 964 goto free_newinfo_counters_untrans;
965 }
919 966
920 /* You lied! */ 967 /* You lied! */
921 if (tmp.valid_hooks != t->valid_hooks) { 968 if (tmp.valid_hooks != t->valid_hooks) {
922 duprintf("Valid hook crap: %08X vs %08X\n", 969 duprintf("Valid hook crap: %08X vs %08X\n",
923 tmp.valid_hooks, t->valid_hooks); 970 tmp.valid_hooks, t->valid_hooks);
924 ret = -EINVAL; 971 ret = -EINVAL;
925 goto free_newinfo_counters_untrans_unlock; 972 goto put_module;
926 }
927
928 /* Get a reference in advance, we're not allowed fail later */
929 if (!try_module_get(t->me)) {
930 ret = -EBUSY;
931 goto free_newinfo_counters_untrans_unlock;
932 } 973 }
933 974
934 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); 975 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret);
@@ -959,7 +1000,6 @@ static int do_replace(void __user *user, unsigned int len)
959 1000
960 put_module: 1001 put_module:
961 module_put(t->me); 1002 module_put(t->me);
962 free_newinfo_counters_untrans_unlock:
963 up(&arpt_mutex); 1003 up(&arpt_mutex);
964 free_newinfo_counters_untrans: 1004 free_newinfo_counters_untrans:
965 ARPT_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry, NULL); 1005 ARPT_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry, NULL);
@@ -989,7 +1029,7 @@ static int do_add_counters(void __user *user, unsigned int len)
989 unsigned int i; 1029 unsigned int i;
990 struct arpt_counters_info tmp, *paddc; 1030 struct arpt_counters_info tmp, *paddc;
991 struct arpt_table *t; 1031 struct arpt_table *t;
992 int ret; 1032 int ret = 0;
993 1033
994 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) 1034 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0)
995 return -EFAULT; 1035 return -EFAULT;
@@ -1006,9 +1046,11 @@ static int do_add_counters(void __user *user, unsigned int len)
1006 goto free; 1046 goto free;
1007 } 1047 }
1008 1048
1009 t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex); 1049 t = find_table_lock(tmp.name);
1010 if (!t) 1050 if (!t || IS_ERR(t)) {
1051 ret = t ? PTR_ERR(t) : -ENOENT;
1011 goto free; 1052 goto free;
1053 }
1012 1054
1013 write_lock_bh(&t->lock); 1055 write_lock_bh(&t->lock);
1014 if (t->private->number != paddc->num_counters) { 1056 if (t->private->number != paddc->num_counters) {
@@ -1025,6 +1067,7 @@ static int do_add_counters(void __user *user, unsigned int len)
1025 unlock_up_free: 1067 unlock_up_free:
1026 write_unlock_bh(&t->lock); 1068 write_unlock_bh(&t->lock);
1027 up(&arpt_mutex); 1069 up(&arpt_mutex);
1070 module_put(t->me);
1028 free: 1071 free:
1029 vfree(paddc); 1072 vfree(paddc);
1030 1073
@@ -1079,8 +1122,10 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
1079 break; 1122 break;
1080 } 1123 }
1081 name[ARPT_TABLE_MAXNAMELEN-1] = '\0'; 1124 name[ARPT_TABLE_MAXNAMELEN-1] = '\0';
1082 t = arpt_find_table_lock(name, &ret, &arpt_mutex); 1125
1083 if (t) { 1126 t = try_then_request_module(find_table_lock(name),
1127 "arptable_%s", name);
1128 if (t && !IS_ERR(t)) {
1084 struct arpt_getinfo info; 1129 struct arpt_getinfo info;
1085 1130
1086 info.valid_hooks = t->valid_hooks; 1131 info.valid_hooks = t->valid_hooks;
@@ -1096,9 +1141,10 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
1096 ret = -EFAULT; 1141 ret = -EFAULT;
1097 else 1142 else
1098 ret = 0; 1143 ret = 0;
1099
1100 up(&arpt_mutex); 1144 up(&arpt_mutex);
1101 } 1145 module_put(t->me);
1146 } else
1147 ret = t ? PTR_ERR(t) : -ENOENT;
1102 } 1148 }
1103 break; 1149 break;
1104 1150
@@ -1119,6 +1165,24 @@ static int do_arpt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len
1119 break; 1165 break;
1120 } 1166 }
1121 1167
1168 case ARPT_SO_GET_REVISION_TARGET: {
1169 struct arpt_get_revision rev;
1170
1171 if (*len != sizeof(rev)) {
1172 ret = -EINVAL;
1173 break;
1174 }
1175 if (copy_from_user(&rev, user, sizeof(rev)) != 0) {
1176 ret = -EFAULT;
1177 break;
1178 }
1179
1180 try_then_request_module(find_revision(rev.name, rev.revision,
1181 target_revfn, &ret),
1182 "arpt_%s", rev.name);
1183 break;
1184 }
1185
1122 default: 1186 default:
1123 duprintf("do_arpt_get_ctl: unknown request %i\n", cmd); 1187 duprintf("do_arpt_get_ctl: unknown request %i\n", cmd);
1124 ret = -EINVAL; 1188 ret = -EINVAL;
@@ -1136,12 +1200,9 @@ int arpt_register_target(struct arpt_target *target)
1136 if (ret != 0) 1200 if (ret != 0)
1137 return ret; 1201 return ret;
1138 1202
1139 if (!list_named_insert(&arpt_target, target)) { 1203 list_add(&target->list, &arpt_target);
1140 duprintf("arpt_register_target: `%s' already in list!\n",
1141 target->name);
1142 ret = -EINVAL;
1143 }
1144 up(&arpt_mutex); 1204 up(&arpt_mutex);
1205
1145 return ret; 1206 return ret;
1146} 1207}
1147 1208
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{