aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-06-28 21:33:24 -0400
committerDavid S. Miller <davem@davemloft.net>2012-06-28 21:33:58 -0400
commita207a4b2e8067cbc7f33924e7f2c0fa4ef43b459 (patch)
tree78e6b5e66b8dd0f1a3609828461d8743397f40b2 /net
parent58050fce3530939372e6c2f4b4beb76fcb4caa65 (diff)
ipv4: Fix bugs in fib_compute_spec_dst().
Based upon feedback from Julian Anastasov. 1) Use route flags to determine multicast/broadcast, not the packet flags. 2) Leave saddr unspecified in flow key. 3) Adjust how we invoke inet_select_addr(). Pass ip_hdr(skb)->saddr as second arg, and if it was zeronet use link scope. 4) Use loopback as input interface in flow key. Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv4/fib_frontend.c34
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):