diff --git a/[refs] b/[refs] index c41b2e6c30ea..447f73912376 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 58050fce3530939372e6c2f4b4beb76fcb4caa65 +refs/heads/master: a207a4b2e8067cbc7f33924e7f2c0fa4ef43b459 diff --git a/trunk/net/ipv4/fib_frontend.c b/trunk/net/ipv4/fib_frontend.c index 63b11ca54d95..1d13217e01ff 100644 --- a/trunk/net/ipv4/fib_frontend.c +++ b/trunk/net/ipv4/fib_frontend.c @@ -185,28 +185,36 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) struct net_device *dev = skb->dev; struct in_device *in_dev; struct fib_result res; + struct rtable *rt; struct flowi4 fl4; struct net *net; + int scope; - if (skb->pkt_type != PACKET_BROADCAST && - skb->pkt_type != PACKET_MULTICAST) + rt = skb_rtable(skb); + if (!(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) return ip_hdr(skb)->daddr; in_dev = __in_dev_get_rcu(dev); BUG_ON(!in_dev); - fl4.flowi4_oif = 0; - fl4.flowi4_iif = 0; - fl4.daddr = ip_hdr(skb)->saddr; - fl4.saddr = ip_hdr(skb)->daddr; - fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); - fl4.flowi4_scope = RT_SCOPE_UNIVERSE; - fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; net = dev_net(dev); - if (!fib_lookup(net, &fl4, &res)) - return FIB_RES_PREFSRC(net, res); - else - return inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); + + scope = RT_SCOPE_UNIVERSE; + if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) { + fl4.flowi4_oif = 0; + fl4.flowi4_iif = net->loopback_dev->ifindex; + fl4.daddr = ip_hdr(skb)->saddr; + fl4.saddr = 0; + fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); + fl4.flowi4_scope = scope; + fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; + if (!fib_lookup(net, &fl4, &res)) + return FIB_RES_PREFSRC(net, res); + } else { + scope = RT_SCOPE_LINK; + } + + return inet_select_addr(dev, ip_hdr(skb)->saddr, scope); } /* Given (packet source, input interface) and optional (dst, oif, tos):