diff options
Diffstat (limited to 'net/ipv6')
| -rw-r--r-- | net/ipv6/addrconf.c | 2 | ||||
| -rw-r--r-- | net/ipv6/mcast.c | 23 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6_tables.c | 298 | ||||
| -rw-r--r-- | net/ipv6/netfilter/ip6t_MARK.c | 8 | ||||
| -rw-r--r-- | net/ipv6/route.c | 2 |
5 files changed, 214 insertions, 119 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 41edc14851e8..2c5f57299d63 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c | |||
| @@ -2163,7 +2163,7 @@ static int addrconf_ifdown(struct net_device *dev, int how) | |||
| 2163 | 2163 | ||
| 2164 | /* Step 5: netlink notification of this interface */ | 2164 | /* Step 5: netlink notification of this interface */ |
| 2165 | idev->tstamp = jiffies; | 2165 | idev->tstamp = jiffies; |
| 2166 | inet6_ifinfo_notify(RTM_NEWLINK, idev); | 2166 | inet6_ifinfo_notify(RTM_DELLINK, idev); |
| 2167 | 2167 | ||
| 2168 | /* Shot the device (if unregistered) */ | 2168 | /* Shot the device (if unregistered) */ |
| 2169 | 2169 | ||
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index c4f2a0ef7489..f15e04ad026e 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c | |||
| @@ -545,8 +545,10 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf) | |||
| 545 | sock_kfree_s(sk, newpsl, IP6_SFLSIZE(newpsl->sl_max)); | 545 | sock_kfree_s(sk, newpsl, IP6_SFLSIZE(newpsl->sl_max)); |
| 546 | goto done; | 546 | goto done; |
| 547 | } | 547 | } |
| 548 | } else | 548 | } else { |
| 549 | newpsl = NULL; | 549 | newpsl = NULL; |
| 550 | (void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0); | ||
| 551 | } | ||
| 550 | psl = pmc->sflist; | 552 | psl = pmc->sflist; |
| 551 | if (psl) { | 553 | if (psl) { |
| 552 | (void) ip6_mc_del_src(idev, group, pmc->sfmode, | 554 | (void) ip6_mc_del_src(idev, group, pmc->sfmode, |
| @@ -1087,7 +1089,7 @@ static void mld_marksources(struct ifmcaddr6 *pmc, int nsrcs, | |||
| 1087 | 1089 | ||
| 1088 | int igmp6_event_query(struct sk_buff *skb) | 1090 | int igmp6_event_query(struct sk_buff *skb) |
| 1089 | { | 1091 | { |
| 1090 | struct mld2_query *mlh2 = (struct mld2_query *) skb->h.raw; | 1092 | struct mld2_query *mlh2 = NULL; |
| 1091 | struct ifmcaddr6 *ma; | 1093 | struct ifmcaddr6 *ma; |
| 1092 | struct in6_addr *group; | 1094 | struct in6_addr *group; |
| 1093 | unsigned long max_delay; | 1095 | unsigned long max_delay; |
| @@ -1140,6 +1142,13 @@ int igmp6_event_query(struct sk_buff *skb) | |||
| 1140 | /* clear deleted report items */ | 1142 | /* clear deleted report items */ |
| 1141 | mld_clear_delrec(idev); | 1143 | mld_clear_delrec(idev); |
| 1142 | } else if (len >= 28) { | 1144 | } else if (len >= 28) { |
| 1145 | int srcs_offset = sizeof(struct mld2_query) - | ||
| 1146 | sizeof(struct icmp6hdr); | ||
| 1147 | if (!pskb_may_pull(skb, srcs_offset)) { | ||
| 1148 | in6_dev_put(idev); | ||
| 1149 | return -EINVAL; | ||
| 1150 | } | ||
| 1151 | mlh2 = (struct mld2_query *) skb->h.raw; | ||
| 1143 | max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000; | 1152 | max_delay = (MLDV2_MRC(ntohs(mlh2->mrc))*HZ)/1000; |
| 1144 | if (!max_delay) | 1153 | if (!max_delay) |
| 1145 | max_delay = 1; | 1154 | max_delay = 1; |
| @@ -1156,7 +1165,15 @@ int igmp6_event_query(struct sk_buff *skb) | |||
| 1156 | return 0; | 1165 | return 0; |
| 1157 | } | 1166 | } |
| 1158 | /* mark sources to include, if group & source-specific */ | 1167 | /* mark sources to include, if group & source-specific */ |
| 1159 | mark = mlh2->nsrcs != 0; | 1168 | if (mlh2->nsrcs != 0) { |
| 1169 | if (!pskb_may_pull(skb, srcs_offset + | ||
| 1170 | mlh2->nsrcs * sizeof(struct in6_addr))) { | ||
| 1171 | in6_dev_put(idev); | ||
| 1172 | return -EINVAL; | ||
| 1173 | } | ||
| 1174 | mlh2 = (struct mld2_query *) skb->h.raw; | ||
| 1175 | mark = 1; | ||
| 1176 | } | ||
| 1160 | } else { | 1177 | } else { |
| 1161 | in6_dev_put(idev); | 1178 | in6_dev_put(idev); |
| 1162 | return -EINVAL; | 1179 | return -EINVAL; |
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 | /* |
| 501 | static inline void * | 498 | * These are weird, but module loading must not be done with mutex |
| 502 | find_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. */ | ||
| 504 | static 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. */ | ||
| 519 | static 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)) | 543 | static inline struct ip6t_target *find_target(const char *name, u8 revision) |
| 530 | #else | ||
| 531 | static void * | ||
| 532 | find_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; | 566 | struct 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 | ||
| 551 | static inline struct ip6t_table * | 577 | static int match_revfn(const char *name, u8 revision, int *bestp) |
| 552 | ip6t_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 | ||
| 557 | static inline struct ip6t_match * | 593 | static int target_revfn(const char *name, u8 revision, int *bestp) |
| 558 | find_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 | ||
| 563 | static struct ip6t_target * | 609 | /* Returns true or fals (if no such extension at all) */ |
| 564 | ip6t_find_target_lock(const char *name, int *error, struct semaphore *mutex) | 610 | static 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. */ |
| 570 | static inline int | 637 | static inline int |
| 571 | unconditional(const struct ip6t_ip6 *ipv6) | 638 | unconditional(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 | ||
| 59 | static struct ip6t_target ip6t_mark_reg | 59 | static 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 | ||
| 62 | static int __init init(void) | 66 | static int __init init(void) |
| 63 | { | 67 | { |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 5d5bbb49ec78..227e99ed510c 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
| @@ -483,7 +483,7 @@ restart: | |||
| 483 | goto out; | 483 | goto out; |
| 484 | } | 484 | } |
| 485 | 485 | ||
| 486 | rt = rt6_device_match(rt, skb->dev->ifindex, 0); | 486 | rt = rt6_device_match(rt, skb->dev->ifindex, strict); |
| 487 | BACKTRACK(); | 487 | BACKTRACK(); |
| 488 | 488 | ||
| 489 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { | 489 | if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { |
