diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/fib_frontend.c | 34 |
1 files changed, 21 insertions, 13 deletions
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 63b11ca54d95..1d13217e01ff 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c | |||
@@ -185,28 +185,36 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb) | |||
185 | struct net_device *dev = skb->dev; | 185 | struct net_device *dev = skb->dev; |
186 | struct in_device *in_dev; | 186 | struct in_device *in_dev; |
187 | struct fib_result res; | 187 | struct fib_result res; |
188 | struct rtable *rt; | ||
188 | struct flowi4 fl4; | 189 | struct flowi4 fl4; |
189 | struct net *net; | 190 | struct net *net; |
191 | int scope; | ||
190 | 192 | ||
191 | if (skb->pkt_type != PACKET_BROADCAST && | 193 | rt = skb_rtable(skb); |
192 | skb->pkt_type != PACKET_MULTICAST) | 194 | if (!(rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))) |
193 | return ip_hdr(skb)->daddr; | 195 | return ip_hdr(skb)->daddr; |
194 | 196 | ||
195 | in_dev = __in_dev_get_rcu(dev); | 197 | in_dev = __in_dev_get_rcu(dev); |
196 | BUG_ON(!in_dev); | 198 | BUG_ON(!in_dev); |
197 | fl4.flowi4_oif = 0; | ||
198 | fl4.flowi4_iif = 0; | ||
199 | fl4.daddr = ip_hdr(skb)->saddr; | ||
200 | fl4.saddr = ip_hdr(skb)->daddr; | ||
201 | fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); | ||
202 | fl4.flowi4_scope = RT_SCOPE_UNIVERSE; | ||
203 | fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; | ||
204 | 199 | ||
205 | net = dev_net(dev); | 200 | net = dev_net(dev); |
206 | if (!fib_lookup(net, &fl4, &res)) | 201 | |
207 | return FIB_RES_PREFSRC(net, res); | 202 | scope = RT_SCOPE_UNIVERSE; |
208 | else | 203 | if (!ipv4_is_zeronet(ip_hdr(skb)->saddr)) { |
209 | return inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE); | 204 | fl4.flowi4_oif = 0; |
205 | fl4.flowi4_iif = net->loopback_dev->ifindex; | ||
206 | fl4.daddr = ip_hdr(skb)->saddr; | ||
207 | fl4.saddr = 0; | ||
208 | fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); | ||
209 | fl4.flowi4_scope = scope; | ||
210 | fl4.flowi4_mark = IN_DEV_SRC_VMARK(in_dev) ? skb->mark : 0; | ||
211 | if (!fib_lookup(net, &fl4, &res)) | ||
212 | return FIB_RES_PREFSRC(net, res); | ||
213 | } else { | ||
214 | scope = RT_SCOPE_LINK; | ||
215 | } | ||
216 | |||
217 | return inet_select_addr(dev, ip_hdr(skb)->saddr, scope); | ||
210 | } | 218 | } |
211 | 219 | ||
212 | /* Given (packet source, input interface) and optional (dst, oif, tos): | 220 | /* Given (packet source, input interface) and optional (dst, oif, tos): |