diff options
-rw-r--r-- | net/ipv4/devinet.c | 4 | ||||
-rw-r--r-- | net/ipv4/fib_frontend.c | 4 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_masquerade_ipv4.c | 12 |
3 files changed, 18 insertions, 2 deletions
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 65e76a48382c..e333bc86bd39 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c | |||
@@ -334,6 +334,9 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
334 | 334 | ||
335 | ASSERT_RTNL(); | 335 | ASSERT_RTNL(); |
336 | 336 | ||
337 | if (in_dev->dead) | ||
338 | goto no_promotions; | ||
339 | |||
337 | /* 1. Deleting primary ifaddr forces deletion all secondaries | 340 | /* 1. Deleting primary ifaddr forces deletion all secondaries |
338 | * unless alias promotion is set | 341 | * unless alias promotion is set |
339 | **/ | 342 | **/ |
@@ -380,6 +383,7 @@ static void __inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, | |||
380 | fib_del_ifaddr(ifa, ifa1); | 383 | fib_del_ifaddr(ifa, ifa1); |
381 | } | 384 | } |
382 | 385 | ||
386 | no_promotions: | ||
383 | /* 2. Unlink it */ | 387 | /* 2. Unlink it */ |
384 | 388 | ||
385 | *ifap = ifa1->ifa_next; | 389 | *ifap = ifa1->ifa_next; |
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 473447593060..21add552e56a 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -922,6 +922,9 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) | |||
922 | subnet = 1; | 922 | subnet = 1; |
923 | } | 923 | } |
924 | 924 | ||
925 | if (in_dev->dead) | ||
926 | goto no_promotions; | ||
927 | |||
925 | /* Deletion is more complicated than add. | 928 | /* Deletion is more complicated than add. |
926 | * We should take care of not to delete too much :-) | 929 | * We should take care of not to delete too much :-) |
927 | * | 930 | * |
@@ -997,6 +1000,7 @@ void fib_del_ifaddr(struct in_ifaddr *ifa, struct in_ifaddr *iprim) | |||
997 | } | 1000 | } |
998 | } | 1001 | } |
999 | 1002 | ||
1003 | no_promotions: | ||
1000 | if (!(ok & BRD_OK)) | 1004 | if (!(ok & BRD_OK)) |
1001 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); | 1005 | fib_magic(RTM_DELROUTE, RTN_BROADCAST, ifa->ifa_broadcast, 32, prim); |
1002 | if (subnet && ifa->ifa_prefixlen < 31) { | 1006 | if (subnet && ifa->ifa_prefixlen < 31) { |
diff --git a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c index c6eb42100e9a..ea91058b5f6f 100644 --- a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c +++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c | |||
@@ -108,10 +108,18 @@ static int masq_inet_event(struct notifier_block *this, | |||
108 | unsigned long event, | 108 | unsigned long event, |
109 | void *ptr) | 109 | void *ptr) |
110 | { | 110 | { |
111 | struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev; | 111 | struct in_device *idev = ((struct in_ifaddr *)ptr)->ifa_dev; |
112 | struct netdev_notifier_info info; | 112 | struct netdev_notifier_info info; |
113 | 113 | ||
114 | netdev_notifier_info_init(&info, dev); | 114 | /* The masq_dev_notifier will catch the case of the device going |
115 | * down. So if the inetdev is dead and being destroyed we have | ||
116 | * no work to do. Otherwise this is an individual address removal | ||
117 | * and we have to perform the flush. | ||
118 | */ | ||
119 | if (idev->dead) | ||
120 | return NOTIFY_DONE; | ||
121 | |||
122 | netdev_notifier_info_init(&info, idev->dev); | ||
115 | return masq_device_event(this, event, &info); | 123 | return masq_device_event(this, event, &info); |
116 | } | 124 | } |
117 | 125 | ||