diff options
author | YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> | 2006-08-23 20:18:26 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-09-22 17:55:42 -0400 |
commit | a6279458c534d01ccc39498aba61c93083ee0372 (patch) | |
tree | aeca5c6e3e54345bd35f8217e705f90f414d9452 | |
parent | 5e032e32ecc2e6cb0385dc115ca9bfe5e19a9539 (diff) |
[IPV6] NDISC: Search over all possible rules on receipt of redirect.
Split up function for finding routes for redirects.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv6/route.c | 85 |
1 files changed, 61 insertions, 24 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index a9b08a2422e0..8d00a9d77f01 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -1279,19 +1279,18 @@ static int ip6_route_del(struct fib6_config *cfg) | |||
1279 | /* | 1279 | /* |
1280 | * Handle redirects | 1280 | * Handle redirects |
1281 | */ | 1281 | */ |
1282 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | 1282 | struct ip6rd_flowi { |
1283 | struct in6_addr *saddr, | 1283 | struct flowi fl; |
1284 | struct neighbour *neigh, u8 *lladdr, int on_link) | 1284 | struct in6_addr gateway; |
1285 | }; | ||
1286 | |||
1287 | static struct rt6_info *__ip6_route_redirect(struct fib6_table *table, | ||
1288 | struct flowi *fl, | ||
1289 | int flags) | ||
1285 | { | 1290 | { |
1286 | struct rt6_info *rt, *nrt = NULL; | 1291 | struct ip6rd_flowi *rdfl = (struct ip6rd_flowi *)fl; |
1292 | struct rt6_info *rt; | ||
1287 | struct fib6_node *fn; | 1293 | struct fib6_node *fn; |
1288 | struct fib6_table *table; | ||
1289 | struct netevent_redirect netevent; | ||
1290 | |||
1291 | /* TODO: Very lazy, might need to check all tables */ | ||
1292 | table = fib6_get_table(RT6_TABLE_MAIN); | ||
1293 | if (table == NULL) | ||
1294 | return; | ||
1295 | 1294 | ||
1296 | /* | 1295 | /* |
1297 | * Get the "current" route for this destination and | 1296 | * Get the "current" route for this destination and |
@@ -1305,7 +1304,7 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | |||
1305 | */ | 1304 | */ |
1306 | 1305 | ||
1307 | read_lock_bh(&table->tb6_lock); | 1306 | read_lock_bh(&table->tb6_lock); |
1308 | fn = fib6_lookup(&table->tb6_root, dest, src); | 1307 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
1309 | restart: | 1308 | restart: |
1310 | for (rt = fn->leaf; rt; rt = rt->u.next) { | 1309 | for (rt = fn->leaf; rt; rt = rt->u.next) { |
1311 | /* | 1310 | /* |
@@ -1320,29 +1319,67 @@ restart: | |||
1320 | continue; | 1319 | continue; |
1321 | if (!(rt->rt6i_flags & RTF_GATEWAY)) | 1320 | if (!(rt->rt6i_flags & RTF_GATEWAY)) |
1322 | continue; | 1321 | continue; |
1323 | if (neigh->dev != rt->rt6i_dev) | 1322 | if (fl->oif != rt->rt6i_dev->ifindex) |
1324 | continue; | 1323 | continue; |
1325 | if (!ipv6_addr_equal(saddr, &rt->rt6i_gateway)) | 1324 | if (!ipv6_addr_equal(&rdfl->gateway, &rt->rt6i_gateway)) |
1326 | continue; | 1325 | continue; |
1327 | break; | 1326 | break; |
1328 | } | 1327 | } |
1329 | if (rt) | 1328 | |
1330 | dst_hold(&rt->u.dst); | 1329 | if (!rt) { |
1331 | else if (rt6_need_strict(dest)) { | 1330 | if (rt6_need_strict(&fl->fl6_dst)) { |
1332 | while ((fn = fn->parent) != NULL) { | 1331 | while ((fn = fn->parent) != NULL) { |
1333 | if (fn->fn_flags & RTN_ROOT) | 1332 | if (fn->fn_flags & RTN_ROOT) |
1334 | break; | 1333 | break; |
1335 | if (fn->fn_flags & RTN_RTINFO) | 1334 | if (fn->fn_flags & RTN_RTINFO) |
1336 | goto restart; | 1335 | goto restart; |
1336 | } | ||
1337 | } | 1337 | } |
1338 | rt = &ip6_null_entry; | ||
1338 | } | 1339 | } |
1340 | dst_hold(&rt->u.dst); | ||
1341 | |||
1339 | read_unlock_bh(&table->tb6_lock); | 1342 | read_unlock_bh(&table->tb6_lock); |
1340 | 1343 | ||
1341 | if (!rt) { | 1344 | return rt; |
1345 | }; | ||
1346 | |||
1347 | static struct rt6_info *ip6_route_redirect(struct in6_addr *dest, | ||
1348 | struct in6_addr *src, | ||
1349 | struct in6_addr *gateway, | ||
1350 | struct net_device *dev) | ||
1351 | { | ||
1352 | struct ip6rd_flowi rdfl = { | ||
1353 | .fl = { | ||
1354 | .oif = dev->ifindex, | ||
1355 | .nl_u = { | ||
1356 | .ip6_u = { | ||
1357 | .daddr = *dest, | ||
1358 | .saddr = *src, | ||
1359 | }, | ||
1360 | }, | ||
1361 | }, | ||
1362 | .gateway = *gateway, | ||
1363 | }; | ||
1364 | int flags = rt6_need_strict(dest) ? RT6_F_STRICT : 0; | ||
1365 | |||
1366 | return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect); | ||
1367 | } | ||
1368 | |||
1369 | void rt6_redirect(struct in6_addr *dest, struct in6_addr *src, | ||
1370 | struct in6_addr *saddr, | ||
1371 | struct neighbour *neigh, u8 *lladdr, int on_link) | ||
1372 | { | ||
1373 | struct rt6_info *rt, *nrt = NULL; | ||
1374 | struct netevent_redirect netevent; | ||
1375 | |||
1376 | rt = ip6_route_redirect(dest, src, saddr, neigh->dev); | ||
1377 | |||
1378 | if (rt == &ip6_null_entry) { | ||
1342 | if (net_ratelimit()) | 1379 | if (net_ratelimit()) |
1343 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " | 1380 | printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " |
1344 | "for redirect target\n"); | 1381 | "for redirect target\n"); |
1345 | return; | 1382 | goto out; |
1346 | } | 1383 | } |
1347 | 1384 | ||
1348 | /* | 1385 | /* |