aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/route.c')
-rw-r--r--net/ipv4/route.c36
1 files changed, 31 insertions, 5 deletions
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 075212e41b83..41557e2bb56e 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -1309,7 +1309,12 @@ static void rt_del(unsigned hash, struct rtable *rt)
1309void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, 1309void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
1310 __be32 saddr, struct net_device *dev) 1310 __be32 saddr, struct net_device *dev)
1311{ 1311{
1312 int s, i;
1312 struct in_device *in_dev = __in_dev_get_rcu(dev); 1313 struct in_device *in_dev = __in_dev_get_rcu(dev);
1314 struct rtable *rt;
1315 __be32 skeys[2] = { saddr, 0 };
1316 int ikeys[2] = { dev->ifindex, 0 };
1317 struct flowi4 fl4;
1313 struct inet_peer *peer; 1318 struct inet_peer *peer;
1314 struct net *net; 1319 struct net *net;
1315 1320
@@ -1332,13 +1337,34 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw,
1332 goto reject_redirect; 1337 goto reject_redirect;
1333 } 1338 }
1334 1339
1335 peer = inet_getpeer_v4(daddr, 1); 1340 memset(&fl4, 0, sizeof(fl4));
1336 if (peer) { 1341 fl4.daddr = daddr;
1337 peer->redirect_learned.a4 = new_gw; 1342 for (s = 0; s < 2; s++) {
1343 for (i = 0; i < 2; i++) {
1344 fl4.flowi4_oif = ikeys[i];
1345 fl4.saddr = skeys[s];
1346 rt = __ip_route_output_key(net, &fl4);
1347 if (IS_ERR(rt))
1348 continue;
1338 1349
1339 inet_putpeer(peer); 1350 if (rt->dst.error || rt->dst.dev != dev ||
1351 rt->rt_gateway != old_gw) {
1352 ip_rt_put(rt);
1353 continue;
1354 }
1340 1355
1341 atomic_inc(&__rt_peer_genid); 1356 if (!rt->peer)
1357 rt_bind_peer(rt, rt->rt_dst, 1);
1358
1359 peer = rt->peer;
1360 if (peer) {
1361 peer->redirect_learned.a4 = new_gw;
1362 atomic_inc(&__rt_peer_genid);
1363 }
1364
1365 ip_rt_put(rt);
1366 return;
1367 }
1342 } 1368 }
1343 return; 1369 return;
1344 1370