Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Harald Welte and committed by
Arnaldo Carvalho de Melo
6b7d31fc 6ede2463

+373 -203
+17 -3
include/linux/netfilter_arp/arp_tables.h
··· 68 68 u_int16_t target_size; 69 69 70 70 /* Used by userspace */ 71 - char name[ARPT_FUNCTION_MAXNAMELEN]; 71 + char name[ARPT_FUNCTION_MAXNAMELEN-1]; 72 + u_int8_t revision; 72 73 } user; 73 74 struct { 74 75 u_int16_t target_size; ··· 149 148 150 149 #define ARPT_SO_GET_INFO (ARPT_BASE_CTL) 151 150 #define ARPT_SO_GET_ENTRIES (ARPT_BASE_CTL + 1) 152 - #define ARPT_SO_GET_MAX ARPT_SO_GET_ENTRIES 151 + /* #define ARPT_SO_GET_REVISION_MATCH (ARPT_BASE_CTL + 2)*/ 152 + #define ARPT_SO_GET_REVISION_TARGET (ARPT_BASE_CTL + 3) 153 + #define ARPT_SO_GET_MAX ARPT_SO_GET_REVISION_TARGET 153 154 154 155 /* CONTINUE verdict for targets */ 155 156 #define ARPT_CONTINUE 0xFFFFFFFF ··· 239 236 struct arpt_entry entrytable[0]; 240 237 }; 241 238 239 + /* The argument to ARPT_SO_GET_REVISION_*. Returns highest revision 240 + * kernel supports, if >= revision. */ 241 + struct arpt_get_revision 242 + { 243 + char name[ARPT_FUNCTION_MAXNAMELEN-1]; 244 + 245 + u_int8_t revision; 246 + }; 247 + 242 248 /* Standard return verdict, or do jump. */ 243 249 #define ARPT_STANDARD_TARGET "" 244 250 /* Error verdict. */ ··· 286 274 { 287 275 struct list_head list; 288 276 289 - const char name[ARPT_FUNCTION_MAXNAMELEN]; 277 + const char name[ARPT_FUNCTION_MAXNAMELEN-1]; 278 + 279 + u_int8_t revision; 290 280 291 281 /* Returns verdict. */ 292 282 unsigned int (*target)(struct sk_buff **pskb,
+22 -5
include/linux/netfilter_ipv6/ip6_tables.h
··· 57 57 u_int16_t match_size; 58 58 59 59 /* Used by userspace */ 60 - char name[IP6T_FUNCTION_MAXNAMELEN]; 60 + char name[IP6T_FUNCTION_MAXNAMELEN-1]; 61 + u_int8_t revision; 61 62 } user; 62 63 struct { 63 64 u_int16_t match_size; ··· 81 80 u_int16_t target_size; 82 81 83 82 /* Used by userspace */ 84 - char name[IP6T_FUNCTION_MAXNAMELEN]; 83 + char name[IP6T_FUNCTION_MAXNAMELEN-1]; 84 + u_int8_t revision; 85 85 } user; 86 86 struct { 87 87 u_int16_t target_size; ··· 163 161 164 162 #define IP6T_SO_GET_INFO (IP6T_BASE_CTL) 165 163 #define IP6T_SO_GET_ENTRIES (IP6T_BASE_CTL + 1) 166 - #define IP6T_SO_GET_MAX IP6T_SO_GET_ENTRIES 164 + #define IP6T_SO_GET_REVISION_MATCH (IP6T_BASE_CTL + 2) 165 + #define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 3) 166 + #define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET 167 167 168 168 /* CONTINUE verdict for targets */ 169 169 #define IP6T_CONTINUE 0xFFFFFFFF ··· 295 291 struct ip6t_entry entrytable[0]; 296 292 }; 297 293 294 + /* The argument to IP6T_SO_GET_REVISION_*. Returns highest revision 295 + * kernel supports, if >= revision. */ 296 + struct ip6t_get_revision 297 + { 298 + char name[IP6T_FUNCTION_MAXNAMELEN-1]; 299 + 300 + u_int8_t revision; 301 + }; 302 + 298 303 /* Standard return verdict, or do jump. */ 299 304 #define IP6T_STANDARD_TARGET "" 300 305 /* Error verdict. */ ··· 365 352 { 366 353 struct list_head list; 367 354 368 - const char name[IP6T_FUNCTION_MAXNAMELEN]; 355 + const char name[IP6T_FUNCTION_MAXNAMELEN-1]; 356 + 357 + u_int8_t revision; 369 358 370 359 /* Return true or false: return FALSE and set *hotdrop = 1 to 371 360 force immediate packet drop. */ ··· 402 387 { 403 388 struct list_head list; 404 389 405 - const char name[IP6T_FUNCTION_MAXNAMELEN]; 390 + const char name[IP6T_FUNCTION_MAXNAMELEN-1]; 391 + 392 + u_int8_t revision; 406 393 407 394 /* Returns verdict. Argument order changed since 2.6.9, as this 408 395 must now handle non-linear skbs, using skb_copy_bits and
+135 -74
net/ipv4/netfilter/arp_tables.c
··· 347 347 return verdict; 348 348 } 349 349 350 - static inline void *find_inlist_lock_noload(struct list_head *head, 351 - const char *name, 352 - int *error, 353 - struct semaphore *mutex) 354 - { 355 - void *ret; 350 + /* 351 + * These are weird, but module loading must not be done with mutex 352 + * held (since they will register), and we have to have a single 353 + * function to use try_then_request_module(). 354 + */ 356 355 357 - *error = down_interruptible(mutex); 358 - if (*error != 0) 356 + /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ 357 + static inline struct arpt_table *find_table_lock(const char *name) 358 + { 359 + struct arpt_table *t; 360 + 361 + if (down_interruptible(&arpt_mutex) != 0) 362 + return ERR_PTR(-EINTR); 363 + 364 + list_for_each_entry(t, &arpt_tables, list) 365 + if (strcmp(t->name, name) == 0 && try_module_get(t->me)) 366 + return t; 367 + up(&arpt_mutex); 368 + return NULL; 369 + } 370 + 371 + 372 + /* Find target, grabs ref. Returns ERR_PTR() on error. */ 373 + static inline struct arpt_target *find_target(const char *name, u8 revision) 374 + { 375 + struct arpt_target *t; 376 + int err = 0; 377 + 378 + if (down_interruptible(&arpt_mutex) != 0) 379 + return ERR_PTR(-EINTR); 380 + 381 + list_for_each_entry(t, &arpt_target, list) { 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 + } 391 + } 392 + up(&arpt_mutex); 393 + return ERR_PTR(err); 394 + } 395 + 396 + struct 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) 359 403 return NULL; 404 + return target; 405 + } 360 406 361 - ret = list_named_find(head, name); 362 - if (!ret) { 363 - *error = -ENOENT; 364 - up(mutex); 407 + static int target_revfn(const char *name, u8 revision, int *bestp) 408 + { 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 + } 365 419 } 366 - return ret; 420 + return have_rev; 367 421 } 368 422 369 - #ifndef CONFIG_KMOD 370 - #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) 371 - #else 372 - static void * 373 - find_inlist_lock(struct list_head *head, 374 - const char *name, 375 - const char *prefix, 376 - int *error, 377 - struct semaphore *mutex) 423 + /* Returns true or false (if no such extension at all) */ 424 + static inline int find_revision(const char *name, u8 revision, 425 + int (*revfn)(const char *, u8, int *), 426 + int *err) 378 427 { 379 - void *ret; 428 + int have_rev, best = -1; 380 429 381 - ret = find_inlist_lock_noload(head, name, error, mutex); 382 - if (!ret) { 383 - duprintf("find_inlist: loading `%s%s'.\n", prefix, name); 384 - request_module("%s%s", prefix, name); 385 - ret = find_inlist_lock_noload(head, name, error, mutex); 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; 386 441 } 387 442 388 - return ret; 389 - } 390 - #endif 391 - 392 - static inline struct arpt_table *arpt_find_table_lock(const char *name, int *error, struct semaphore *mutex) 393 - { 394 - return find_inlist_lock(&arpt_tables, name, "arptable_", error, mutex); 443 + *err = best; 444 + if (!have_rev) 445 + *err = -EPROTONOSUPPORT; 446 + return 1; 395 447 } 396 448 397 - static struct arpt_target *arpt_find_target_lock(const char *name, int *error, struct semaphore *mutex) 398 - { 399 - return find_inlist_lock(&arpt_target, name, "arpt_", error, mutex); 400 - } 401 449 402 450 /* All zeroes == unconditional rule. */ 403 451 static inline int unconditional(const struct arpt_arp *arp) ··· 592 544 } 593 545 594 546 t = arpt_get_target(e); 595 - target = arpt_find_target_lock(t->u.user.name, &ret, &arpt_mutex); 596 - if (!target) { 547 + target = try_then_request_module(find_target(t->u.user.name, 548 + t->u.user.revision), 549 + "arpt_%s", t->u.user.name); 550 + if (IS_ERR(target) || !target) { 597 551 duprintf("check_entry: `%s' not found\n", t->u.user.name); 552 + ret = target ? PTR_ERR(target) : -ENOENT; 598 553 goto out; 599 554 } 600 - if (!try_module_get((target->me))) { 601 - ret = -ENOENT; 602 - goto out_unlock; 603 - } 604 555 t->u.kernel.target = target; 605 - up(&arpt_mutex); 606 556 607 557 if (t->u.kernel.target == &arpt_standard_target) { 608 558 if (!standard_check(t, size)) { ··· 622 576 (*i)++; 623 577 return 0; 624 578 625 - out_unlock: 626 - up(&arpt_mutex); 627 579 out: 628 580 return ret; 629 581 } ··· 890 846 int ret; 891 847 struct arpt_table *t; 892 848 893 - t = arpt_find_table_lock(entries->name, &ret, &arpt_mutex); 894 - if (t) { 849 + t = find_table_lock(entries->name); 850 + if (t || !IS_ERR(t)) { 895 851 duprintf("t->private->number = %u\n", 896 852 t->private->number); 897 853 if (entries->size == t->private->size) ··· 903 859 entries->size); 904 860 ret = -EINVAL; 905 861 } 862 + module_put(t->me); 906 863 up(&arpt_mutex); 907 864 } else 908 - duprintf("get_entries: Can't find %s!\n", 909 - entries->name); 865 + ret = t ? PTR_ERR(t) : -ENOENT; 910 866 911 867 return ret; 912 868 } ··· 957 913 958 914 duprintf("arp_tables: Translated table\n"); 959 915 960 - t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex); 961 - if (!t) 916 + t = try_then_request_module(find_table_lock(tmp.name), 917 + "arptable_%s", tmp.name); 918 + if (!t || IS_ERR(t)) { 919 + ret = t ? PTR_ERR(t) : -ENOENT; 962 920 goto free_newinfo_counters_untrans; 921 + } 963 922 964 923 /* You lied! */ 965 924 if (tmp.valid_hooks != t->valid_hooks) { 966 925 duprintf("Valid hook crap: %08X vs %08X\n", 967 926 tmp.valid_hooks, t->valid_hooks); 968 927 ret = -EINVAL; 969 - goto free_newinfo_counters_untrans_unlock; 970 - } 971 - 972 - /* Get a reference in advance, we're not allowed fail later */ 973 - if (!try_module_get(t->me)) { 974 - ret = -EBUSY; 975 - goto free_newinfo_counters_untrans_unlock; 928 + goto put_module; 976 929 } 977 930 978 931 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); ··· 1000 959 1001 960 put_module: 1002 961 module_put(t->me); 1003 - free_newinfo_counters_untrans_unlock: 1004 962 up(&arpt_mutex); 1005 963 free_newinfo_counters_untrans: 1006 964 ARPT_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry, NULL); ··· 1029 989 unsigned int i; 1030 990 struct arpt_counters_info tmp, *paddc; 1031 991 struct arpt_table *t; 1032 - int ret; 992 + int ret = 0; 1033 993 1034 994 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) 1035 995 return -EFAULT; ··· 1046 1006 goto free; 1047 1007 } 1048 1008 1049 - t = arpt_find_table_lock(tmp.name, &ret, &arpt_mutex); 1050 - if (!t) 1009 + t = find_table_lock(tmp.name); 1010 + if (!t || IS_ERR(t)) { 1011 + ret = t ? PTR_ERR(t) : -ENOENT; 1051 1012 goto free; 1013 + } 1052 1014 1053 1015 write_lock_bh(&t->lock); 1054 1016 if (t->private->number != paddc->num_counters) { ··· 1067 1025 unlock_up_free: 1068 1026 write_unlock_bh(&t->lock); 1069 1027 up(&arpt_mutex); 1028 + module_put(t->me); 1070 1029 free: 1071 1030 vfree(paddc); 1072 1031 ··· 1122 1079 break; 1123 1080 } 1124 1081 name[ARPT_TABLE_MAXNAMELEN-1] = '\0'; 1125 - t = arpt_find_table_lock(name, &ret, &arpt_mutex); 1126 - if (t) { 1082 + 1083 + t = try_then_request_module(find_table_lock(name), 1084 + "arptable_%s", name); 1085 + if (t && !IS_ERR(t)) { 1127 1086 struct arpt_getinfo info; 1128 1087 1129 1088 info.valid_hooks = t->valid_hooks; ··· 1141 1096 ret = -EFAULT; 1142 1097 else 1143 1098 ret = 0; 1144 - 1145 1099 up(&arpt_mutex); 1146 - } 1100 + module_put(t->me); 1101 + } else 1102 + ret = t ? PTR_ERR(t) : -ENOENT; 1147 1103 } 1148 1104 break; 1149 1105 ··· 1165 1119 break; 1166 1120 } 1167 1121 1122 + case ARPT_SO_GET_REVISION_TARGET: { 1123 + struct arpt_get_revision rev; 1124 + 1125 + if (*len != sizeof(rev)) { 1126 + ret = -EINVAL; 1127 + break; 1128 + } 1129 + if (copy_from_user(&rev, user, sizeof(rev)) != 0) { 1130 + ret = -EFAULT; 1131 + break; 1132 + } 1133 + 1134 + try_then_request_module(find_revision(rev.name, rev.revision, 1135 + target_revfn, &ret), 1136 + "arpt_%s", rev.name); 1137 + break; 1138 + } 1139 + 1168 1140 default: 1169 1141 duprintf("do_arpt_get_ctl: unknown request %i\n", cmd); 1170 1142 ret = -EINVAL; ··· 1200 1136 if (ret != 0) 1201 1137 return ret; 1202 1138 1203 - if (!list_named_insert(&arpt_target, target)) { 1204 - duprintf("arpt_register_target: `%s' already in list!\n", 1205 - target->name); 1206 - ret = -EINVAL; 1207 - } 1139 + list_add(&target->list, &arpt_target); 1208 1140 up(&arpt_mutex); 1141 + 1209 1142 return ret; 1210 1143 } 1211 1144
+193 -119
net/ipv6/netfilter/ip6_tables.c
··· 2 2 * Packet matching code. 3 3 * 4 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 7 * This program is free software; you can redistribute it and/or modify 8 8 * it under the terms of the GNU General Public License version 2 as ··· 23 23 #include <linux/tcp.h> 24 24 #include <linux/udp.h> 25 25 #include <linux/icmpv6.h> 26 - #include <net/ip.h> 27 26 #include <net/ipv6.h> 28 27 #include <asm/uaccess.h> 29 28 #include <asm/semaphore.h> ··· 79 80 #define inline 80 81 #endif 81 82 82 - /* Locking is simple: we assume at worst case there will be one packet 83 - in user context and one from bottom halves (or soft irq if Alexey's 84 - softnet patch was applied). 85 - 83 + /* 86 84 We keep a set of rules for each CPU, so we can avoid write-locking 87 - them; doing a readlock_bh() stops packets coming through if we're 88 - in user context. 85 + them in the softirq when updating the counters and therefore 86 + only need to read-lock in the softirq; doing a write_lock_bh() in user 87 + context stops packets coming through and allows user context to read 88 + the counters or update the rules. 89 89 90 90 To be cache friendly on SMP, we arrange them like so: 91 91 [ n-entries ] ··· 354 356 struct ip6t_table *table, 355 357 void *userdata) 356 358 { 357 - static const char nulldevname[IFNAMSIZ]; 359 + static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); 358 360 int offset = 0; 359 361 unsigned int protoff = 0; 360 362 int hotdrop = 0; ··· 367 369 /* Initialization */ 368 370 indev = in ? in->name : nulldevname; 369 371 outdev = out ? out->name : nulldevname; 370 - 371 372 /* We handle fragments by dealing with the first fragment as 372 373 * if it was a normal packet. All other fragments are treated 373 374 * normally, except that they will NEVER match rules that ask ··· 494 497 #endif 495 498 } 496 499 497 - /* If it succeeds, returns element and locks mutex */ 498 - static inline void * 499 - find_inlist_lock_noload(struct list_head *head, 500 - const char *name, 501 - int *error, 502 - struct semaphore *mutex) 500 + /* 501 + * These are weird, but module loading must not be done with mutex 502 + * held (since they will register), and we have to have a single 503 + * function to use try_then_request_module(). 504 + */ 505 + 506 + /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ 507 + static inline struct ip6t_table *find_table_lock(const char *name) 503 508 { 504 - void *ret; 509 + struct ip6t_table *t; 505 510 506 - #if 1 507 - duprintf("find_inlist: searching for `%s' in %s.\n", 508 - name, head == &ip6t_target ? "ip6t_target" 509 - : head == &ip6t_match ? "ip6t_match" 510 - : head == &ip6t_tables ? "ip6t_tables" : "UNKNOWN"); 511 - #endif 511 + if (down_interruptible(&ip6t_mutex) != 0) 512 + return ERR_PTR(-EINTR); 512 513 513 - *error = down_interruptible(mutex); 514 - if (*error != 0) 514 + list_for_each_entry(t, &ip6t_tables, list) 515 + if (strcmp(t->name, name) == 0 && try_module_get(t->me)) 516 + return t; 517 + up(&ip6t_mutex); 518 + return NULL; 519 + } 520 + 521 + /* Find match, grabs ref. Returns ERR_PTR() on error. */ 522 + static inline struct ip6t_match *find_match(const char *name, u8 revision) 523 + { 524 + struct ip6t_match *m; 525 + int err = 0; 526 + 527 + if (down_interruptible(&ip6t_mutex) != 0) 528 + return ERR_PTR(-EINTR); 529 + 530 + list_for_each_entry(m, &ip6t_match, list) { 531 + if (strcmp(m->name, name) == 0) { 532 + if (m->revision == revision) { 533 + if (try_module_get(m->me)) { 534 + up(&ip6t_mutex); 535 + return m; 536 + } 537 + } else 538 + err = -EPROTOTYPE; /* Found something. */ 539 + } 540 + } 541 + up(&ip6t_mutex); 542 + return ERR_PTR(err); 543 + } 544 + 545 + /* Find target, grabs ref. Returns ERR_PTR() on error. */ 546 + static inline struct ip6t_target *find_target(const char *name, u8 revision) 547 + { 548 + struct ip6t_target *t; 549 + int err = 0; 550 + 551 + if (down_interruptible(&ip6t_mutex) != 0) 552 + return ERR_PTR(-EINTR); 553 + 554 + list_for_each_entry(t, &ip6t_target, list) { 555 + if (strcmp(t->name, name) == 0) { 556 + if (t->revision == revision) { 557 + if (try_module_get(t->me)) { 558 + up(&ip6t_mutex); 559 + return t; 560 + } 561 + } else 562 + err = -EPROTOTYPE; /* Found something. */ 563 + } 564 + } 565 + up(&ip6t_mutex); 566 + return ERR_PTR(err); 567 + } 568 + 569 + struct ip6t_target *ip6t_find_target(const char *name, u8 revision) 570 + { 571 + struct ip6t_target *target; 572 + 573 + target = try_then_request_module(find_target(name, revision), 574 + "ip6t_%s", name); 575 + if (IS_ERR(target) || !target) 515 576 return NULL; 577 + return target; 578 + } 516 579 517 - ret = list_named_find(head, name); 518 - if (!ret) { 519 - *error = -ENOENT; 520 - up(mutex); 580 + static int match_revfn(const char *name, u8 revision, int *bestp) 581 + { 582 + struct ip6t_match *m; 583 + int have_rev = 0; 584 + 585 + list_for_each_entry(m, &ip6t_match, list) { 586 + if (strcmp(m->name, name) == 0) { 587 + if (m->revision > *bestp) 588 + *bestp = m->revision; 589 + if (m->revision == revision) 590 + have_rev = 1; 591 + } 521 592 } 522 - return ret; 593 + return have_rev; 523 594 } 524 595 525 - #ifndef CONFIG_KMOD 526 - #define find_inlist_lock(h,n,p,e,m) find_inlist_lock_noload((h),(n),(e),(m)) 527 - #else 528 - static void * 529 - find_inlist_lock(struct list_head *head, 530 - const char *name, 531 - const char *prefix, 532 - int *error, 533 - struct semaphore *mutex) 596 + static int target_revfn(const char *name, u8 revision, int *bestp) 534 597 { 535 - void *ret; 598 + struct ip6t_target *t; 599 + int have_rev = 0; 536 600 537 - ret = find_inlist_lock_noload(head, name, error, mutex); 538 - if (!ret) { 539 - duprintf("find_inlist: loading `%s%s'.\n", prefix, name); 540 - request_module("%s%s", prefix, name); 541 - ret = find_inlist_lock_noload(head, name, error, mutex); 601 + list_for_each_entry(t, &ip6t_target, list) { 602 + if (strcmp(t->name, name) == 0) { 603 + if (t->revision > *bestp) 604 + *bestp = t->revision; 605 + if (t->revision == revision) 606 + have_rev = 1; 607 + } 608 + } 609 + return have_rev; 610 + } 611 + 612 + /* Returns true or fals (if no such extension at all) */ 613 + static inline int find_revision(const char *name, u8 revision, 614 + int (*revfn)(const char *, u8, int *), 615 + int *err) 616 + { 617 + int have_rev, best = -1; 618 + 619 + if (down_interruptible(&ip6t_mutex) != 0) { 620 + *err = -EINTR; 621 + return 1; 622 + } 623 + have_rev = revfn(name, revision, &best); 624 + up(&ip6t_mutex); 625 + 626 + /* Nothing at all? Return 0 to try loading module. */ 627 + if (best == -1) { 628 + *err = -ENOENT; 629 + return 0; 542 630 } 543 631 544 - return ret; 545 - } 546 - #endif 547 - 548 - static inline struct ip6t_table * 549 - ip6t_find_table_lock(const char *name, int *error, struct semaphore *mutex) 550 - { 551 - return find_inlist_lock(&ip6t_tables, name, "ip6table_", error, mutex); 632 + *err = best; 633 + if (!have_rev) 634 + *err = -EPROTONOSUPPORT; 635 + return 1; 552 636 } 553 637 554 - static inline struct ip6t_match * 555 - find_match_lock(const char *name, int *error, struct semaphore *mutex) 556 - { 557 - return find_inlist_lock(&ip6t_match, name, "ip6t_", error, mutex); 558 - } 559 - 560 - static struct ip6t_target * 561 - ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex) 562 - { 563 - return find_inlist_lock(&ip6t_target, name, "ip6t_", error, mutex); 564 - } 565 638 566 639 /* All zeroes == unconditional rule. */ 567 640 static inline int ··· 792 725 unsigned int hookmask, 793 726 unsigned int *i) 794 727 { 795 - int ret; 796 728 struct ip6t_match *match; 797 729 798 - match = find_match_lock(m->u.user.name, &ret, &ip6t_mutex); 799 - if (!match) { 800 - // duprintf("check_match: `%s' not found\n", m->u.name); 801 - return ret; 802 - } 803 - if (!try_module_get(match->me)) { 804 - up(&ip6t_mutex); 805 - return -ENOENT; 730 + match = try_then_request_module(find_match(m->u.user.name, 731 + m->u.user.revision), 732 + "ip6t_%s", m->u.user.name); 733 + if (IS_ERR(match) || !match) { 734 + duprintf("check_match: `%s' not found\n", m->u.user.name); 735 + return match ? PTR_ERR(match) : -ENOENT; 806 736 } 807 737 m->u.kernel.match = match; 808 - up(&ip6t_mutex); 809 738 810 739 if (m->u.kernel.match->checkentry 811 740 && !m->u.kernel.match->checkentry(name, ipv6, m->data, ··· 839 776 goto cleanup_matches; 840 777 841 778 t = ip6t_get_target(e); 842 - target = ip6t_find_target_lock(t->u.user.name, &ret, &ip6t_mutex); 843 - if (!target) { 779 + target = try_then_request_module(find_target(t->u.user.name, 780 + t->u.user.revision), 781 + "ip6t_%s", t->u.user.name); 782 + if (IS_ERR(target) || !target) { 844 783 duprintf("check_entry: `%s' not found\n", t->u.user.name); 845 - goto cleanup_matches; 846 - } 847 - if (!try_module_get(target->me)) { 848 - up(&ip6t_mutex); 849 - ret = -ENOENT; 784 + ret = target ? PTR_ERR(target) : -ENOENT; 850 785 goto cleanup_matches; 851 786 } 852 787 t->u.kernel.target = target; 853 - up(&ip6t_mutex); 854 - if (!t->u.kernel.target) { 855 - ret = -EBUSY; 856 - goto cleanup_matches; 857 - } 788 + 858 789 if (t->u.kernel.target == &ip6t_standard_target) { 859 790 if (!standard_check(t, size)) { 860 791 ret = -EINVAL; ··· 1175 1118 int ret; 1176 1119 struct ip6t_table *t; 1177 1120 1178 - t = ip6t_find_table_lock(entries->name, &ret, &ip6t_mutex); 1179 - if (t) { 1121 + t = find_table_lock(entries->name); 1122 + if (t && !IS_ERR(t)) { 1180 1123 duprintf("t->private->number = %u\n", 1181 1124 t->private->number); 1182 1125 if (entries->size == t->private->size) ··· 1188 1131 entries->size); 1189 1132 ret = -EINVAL; 1190 1133 } 1134 + module_put(t->me); 1191 1135 up(&ip6t_mutex); 1192 1136 } else 1193 - duprintf("get_entries: Can't find %s!\n", 1194 - entries->name); 1137 + ret = t ? PTR_ERR(t) : -ENOENT; 1195 1138 1196 1139 return ret; 1197 1140 } ··· 1239 1182 1240 1183 duprintf("ip_tables: Translated table\n"); 1241 1184 1242 - t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex); 1243 - if (!t) 1185 + t = try_then_request_module(find_table_lock(tmp.name), 1186 + "ip6table_%s", tmp.name); 1187 + if (!t || IS_ERR(t)) { 1188 + ret = t ? PTR_ERR(t) : -ENOENT; 1244 1189 goto free_newinfo_counters_untrans; 1190 + } 1245 1191 1246 1192 /* You lied! */ 1247 1193 if (tmp.valid_hooks != t->valid_hooks) { 1248 1194 duprintf("Valid hook crap: %08X vs %08X\n", 1249 1195 tmp.valid_hooks, t->valid_hooks); 1250 1196 ret = -EINVAL; 1251 - goto free_newinfo_counters_untrans_unlock; 1252 - } 1253 - 1254 - /* Get a reference in advance, we're not allowed fail later */ 1255 - if (!try_module_get(t->me)) { 1256 - ret = -EBUSY; 1257 - goto free_newinfo_counters_untrans_unlock; 1197 + goto put_module; 1258 1198 } 1259 1199 1260 1200 oldinfo = replace_table(t, tmp.num_counters, newinfo, &ret); ··· 1273 1219 /* Decrease module usage counts and free resource */ 1274 1220 IP6T_ENTRY_ITERATE(oldinfo->entries, oldinfo->size, cleanup_entry,NULL); 1275 1221 vfree(oldinfo); 1276 - /* Silent error: too late now. */ 1277 1222 if (copy_to_user(tmp.counters, counters, 1278 1223 sizeof(struct ip6t_counters) * tmp.num_counters) != 0) 1279 1224 ret = -EFAULT; ··· 1282 1229 1283 1230 put_module: 1284 1231 module_put(t->me); 1285 - free_newinfo_counters_untrans_unlock: 1286 1232 up(&ip6t_mutex); 1287 1233 free_newinfo_counters_untrans: 1288 1234 IP6T_ENTRY_ITERATE(newinfo->entries, newinfo->size, cleanup_entry,NULL); ··· 1320 1268 unsigned int i; 1321 1269 struct ip6t_counters_info tmp, *paddc; 1322 1270 struct ip6t_table *t; 1323 - int ret; 1271 + int ret = 0; 1324 1272 1325 1273 if (copy_from_user(&tmp, user, sizeof(tmp)) != 0) 1326 1274 return -EFAULT; ··· 1337 1285 goto free; 1338 1286 } 1339 1287 1340 - t = ip6t_find_table_lock(tmp.name, &ret, &ip6t_mutex); 1341 - if (!t) 1288 + t = find_table_lock(tmp.name); 1289 + if (!t || IS_ERR(t)) { 1290 + ret = t ? PTR_ERR(t) : -ENOENT; 1342 1291 goto free; 1292 + } 1343 1293 1344 1294 write_lock_bh(&t->lock); 1345 1295 if (t->private->number != paddc->num_counters) { ··· 1358 1304 unlock_up_free: 1359 1305 write_unlock_bh(&t->lock); 1360 1306 up(&ip6t_mutex); 1307 + module_put(t->me); 1361 1308 free: 1362 1309 vfree(paddc); 1363 1310 ··· 1415 1360 break; 1416 1361 } 1417 1362 name[IP6T_TABLE_MAXNAMELEN-1] = '\0'; 1418 - t = ip6t_find_table_lock(name, &ret, &ip6t_mutex); 1419 - if (t) { 1363 + 1364 + t = try_then_request_module(find_table_lock(name), 1365 + "ip6table_%s", name); 1366 + if (t && !IS_ERR(t)) { 1420 1367 struct ip6t_getinfo info; 1421 1368 1422 1369 info.valid_hooks = t->valid_hooks; ··· 1434 1377 ret = -EFAULT; 1435 1378 else 1436 1379 ret = 0; 1437 - 1438 1380 up(&ip6t_mutex); 1439 - } 1381 + module_put(t->me); 1382 + } else 1383 + ret = t ? PTR_ERR(t) : -ENOENT; 1440 1384 } 1441 1385 break; 1442 1386 ··· 1458 1400 break; 1459 1401 } 1460 1402 1403 + case IP6T_SO_GET_REVISION_MATCH: 1404 + case IP6T_SO_GET_REVISION_TARGET: { 1405 + struct ip6t_get_revision rev; 1406 + int (*revfn)(const char *, u8, int *); 1407 + 1408 + if (*len != sizeof(rev)) { 1409 + ret = -EINVAL; 1410 + break; 1411 + } 1412 + if (copy_from_user(&rev, user, sizeof(rev)) != 0) { 1413 + ret = -EFAULT; 1414 + break; 1415 + } 1416 + 1417 + if (cmd == IP6T_SO_GET_REVISION_TARGET) 1418 + revfn = target_revfn; 1419 + else 1420 + revfn = match_revfn; 1421 + 1422 + try_then_request_module(find_revision(rev.name, rev.revision, 1423 + revfn, &ret), 1424 + "ip6t_%s", rev.name); 1425 + break; 1426 + } 1427 + 1461 1428 default: 1462 1429 duprintf("do_ip6t_get_ctl: unknown request %i\n", cmd); 1463 1430 ret = -EINVAL; ··· 1500 1417 ret = down_interruptible(&ip6t_mutex); 1501 1418 if (ret != 0) 1502 1419 return ret; 1503 - 1504 - if (!list_named_insert(&ip6t_target, target)) { 1505 - duprintf("ip6t_register_target: `%s' already in list!\n", 1506 - target->name); 1507 - ret = -EINVAL; 1508 - } 1420 + list_add(&target->list, &ip6t_target); 1509 1421 up(&ip6t_mutex); 1510 1422 return ret; 1511 1423 } ··· 1522 1444 if (ret != 0) 1523 1445 return ret; 1524 1446 1525 - if (!list_named_insert(&ip6t_match, match)) { 1526 - duprintf("ip6t_register_match: `%s' already in list!\n", 1527 - match->name); 1528 - ret = -EINVAL; 1529 - } 1447 + list_add(&match->list, &ip6t_match); 1530 1448 up(&ip6t_mutex); 1531 1449 1532 1450 return ret;
+6 -2
net/ipv6/netfilter/ip6t_MARK.c
··· 56 56 return 1; 57 57 } 58 58 59 - static struct ip6t_target ip6t_mark_reg 60 - = { { NULL, NULL }, "MARK", target, checkentry, NULL, THIS_MODULE }; 59 + static struct ip6t_target ip6t_mark_reg = { 60 + .name = "MARK", 61 + .target = target, 62 + .checkentry = checkentry, 63 + .me = THIS_MODULE 64 + }; 61 65 62 66 static int __init init(void) 63 67 {