aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
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/ipv4
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/ipv4')
-rw-r--r--net/ipv4/netfilter/arp_tables.c201
1 files changed, 131 insertions, 70 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