diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 22 |
1 files changed, 17 insertions, 5 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 751e98f9b8b4..5d6c166dfbb6 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -228,7 +228,7 @@ static __inline__ int rt6_check_expired(const struct rt6_info *rt) | |||
228 | static inline int rt6_need_strict(struct in6_addr *daddr) | 228 | static inline int rt6_need_strict(struct in6_addr *daddr) |
229 | { | 229 | { |
230 | return (ipv6_addr_type(daddr) & | 230 | return (ipv6_addr_type(daddr) & |
231 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL)); | 231 | (IPV6_ADDR_MULTICAST | IPV6_ADDR_LINKLOCAL | IPV6_ADDR_LOOPBACK)); |
232 | } | 232 | } |
233 | 233 | ||
234 | /* | 234 | /* |
@@ -237,15 +237,20 @@ static inline int rt6_need_strict(struct in6_addr *daddr) | |||
237 | 237 | ||
238 | static inline struct rt6_info *rt6_device_match(struct net *net, | 238 | static inline struct rt6_info *rt6_device_match(struct net *net, |
239 | struct rt6_info *rt, | 239 | struct rt6_info *rt, |
240 | struct in6_addr *saddr, | ||
240 | int oif, | 241 | int oif, |
241 | int flags) | 242 | int flags) |
242 | { | 243 | { |
243 | struct rt6_info *local = NULL; | 244 | struct rt6_info *local = NULL; |
244 | struct rt6_info *sprt; | 245 | struct rt6_info *sprt; |
245 | 246 | ||
246 | if (oif) { | 247 | if (!oif && ipv6_addr_any(saddr)) |
247 | for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { | 248 | goto out; |
248 | struct net_device *dev = sprt->rt6i_dev; | 249 | |
250 | for (sprt = rt; sprt; sprt = sprt->u.dst.rt6_next) { | ||
251 | struct net_device *dev = sprt->rt6i_dev; | ||
252 | |||
253 | if (oif) { | ||
249 | if (dev->ifindex == oif) | 254 | if (dev->ifindex == oif) |
250 | return sprt; | 255 | return sprt; |
251 | if (dev->flags & IFF_LOOPBACK) { | 256 | if (dev->flags & IFF_LOOPBACK) { |
@@ -259,14 +264,21 @@ static inline struct rt6_info *rt6_device_match(struct net *net, | |||
259 | } | 264 | } |
260 | local = sprt; | 265 | local = sprt; |
261 | } | 266 | } |
267 | } else { | ||
268 | if (ipv6_chk_addr(net, saddr, dev, | ||
269 | flags & RT6_LOOKUP_F_IFACE)) | ||
270 | return sprt; | ||
262 | } | 271 | } |
272 | } | ||
263 | 273 | ||
274 | if (oif) { | ||
264 | if (local) | 275 | if (local) |
265 | return local; | 276 | return local; |
266 | 277 | ||
267 | if (flags & RT6_LOOKUP_F_IFACE) | 278 | if (flags & RT6_LOOKUP_F_IFACE) |
268 | return net->ipv6.ip6_null_entry; | 279 | return net->ipv6.ip6_null_entry; |
269 | } | 280 | } |
281 | out: | ||
270 | return rt; | 282 | return rt; |
271 | } | 283 | } |
272 | 284 | ||
@@ -539,7 +551,7 @@ static struct rt6_info *ip6_pol_route_lookup(struct net *net, | |||
539 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); | 551 | fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); |
540 | restart: | 552 | restart: |
541 | rt = fn->leaf; | 553 | rt = fn->leaf; |
542 | rt = rt6_device_match(net, rt, fl->oif, flags); | 554 | rt = rt6_device_match(net, rt, &fl->fl6_src, fl->oif, flags); |
543 | BACKTRACK(net, &fl->fl6_src); | 555 | BACKTRACK(net, &fl->fl6_src); |
544 | out: | 556 | out: |
545 | dst_use(&rt->u.dst, jiffies); | 557 | dst_use(&rt->u.dst, jiffies); |