aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/ipv4/devinet.c4
-rw-r--r--net/ipv4/fib_frontend.c4
-rw-r--r--net/ipv4/netfilter/nf_nat_masquerade_ipv4.c12
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
386no_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
1003no_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