aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip_fib.h1
-rw-r--r--net/ipv4/fib_frontend.c29
-rw-r--r--net/ipv4/icmp.c6
-rw-r--r--net/ipv4/ip_options.c22
-rw-r--r--net/ipv4/ip_sockglue.c7
5 files changed, 49 insertions, 16 deletions
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 4b347c0ca094..1687b3de54ff 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.h
@@ -230,6 +230,7 @@ extern struct fib_table *fib_get_table(struct net *net, u32 id);
230/* Exported by fib_frontend.c */ 230/* Exported by fib_frontend.c */
231extern const struct nla_policy rtm_ipv4_policy[]; 231extern const struct nla_policy rtm_ipv4_policy[];
232extern void ip_fib_init(void); 232extern void ip_fib_init(void);
233extern __be32 fib_compute_spec_dst(struct sk_buff *skb);
233extern int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, 234extern int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst,
234 u8 tos, int oif, struct net_device *dev, 235 u8 tos, int oif, struct net_device *dev,
235 __be32 *spec_dst, u32 *itag); 236 __be32 *spec_dst, u32 *itag);
diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
index 3854411fa37c..451939b60c54 100644
--- a/net/ipv4/fib_frontend.c
+++ b/net/ipv4/fib_frontend.c
@@ -180,6 +180,35 @@ unsigned int inet_dev_addr_type(struct net *net, const struct net_device *dev,
180} 180}
181EXPORT_SYMBOL(inet_dev_addr_type); 181EXPORT_SYMBOL(inet_dev_addr_type);
182 182
183__be32 fib_compute_spec_dst(struct sk_buff *skb)
184{
185 struct net_device *dev = skb->dev;
186 struct in_device *in_dev;
187 struct fib_result res;
188 struct flowi4 fl4;
189 struct net *net;
190
191 if (skb->pkt_type != PACKET_BROADCAST &&
192 skb->pkt_type != PACKET_MULTICAST)
193 return ip_hdr(skb)->daddr;
194
195 in_dev = __in_dev_get_rcu(dev);
196 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
205 net = dev_net(dev);
206 if (!fib_lookup(net, &fl4, &res))
207 return FIB_RES_PREFSRC(net, res);
208 else
209 return inet_select_addr(dev, 0, RT_SCOPE_UNIVERSE);
210}
211
183/* Given (packet source, input interface) and optional (dst, oif, tos): 212/* Given (packet source, input interface) and optional (dst, oif, tos):
184 * - (main) check, that source is valid i.e. not broadcast or our local 213 * - (main) check, that source is valid i.e. not broadcast or our local
185 * address. 214 * address.
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index 49a74cc79dc8..4bce5a2830aa 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -95,6 +95,7 @@
95#include <net/checksum.h> 95#include <net/checksum.h>
96#include <net/xfrm.h> 96#include <net/xfrm.h>
97#include <net/inet_common.h> 97#include <net/inet_common.h>
98#include <net/ip_fib.h>
98 99
99/* 100/*
100 * Build xmit assembly blocks 101 * Build xmit assembly blocks
@@ -333,7 +334,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
333 struct flowi4 fl4; 334 struct flowi4 fl4;
334 struct sock *sk; 335 struct sock *sk;
335 struct inet_sock *inet; 336 struct inet_sock *inet;
336 __be32 daddr; 337 __be32 daddr, saddr;
337 338
338 if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb)) 339 if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb))
339 return; 340 return;
@@ -347,6 +348,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
347 348
348 inet->tos = ip_hdr(skb)->tos; 349 inet->tos = ip_hdr(skb)->tos;
349 daddr = ipc.addr = ip_hdr(skb)->saddr; 350 daddr = ipc.addr = ip_hdr(skb)->saddr;
351 saddr = fib_compute_spec_dst(skb);
350 ipc.opt = NULL; 352 ipc.opt = NULL;
351 ipc.tx_flags = 0; 353 ipc.tx_flags = 0;
352 if (icmp_param->replyopts.opt.opt.optlen) { 354 if (icmp_param->replyopts.opt.opt.optlen) {
@@ -356,7 +358,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
356 } 358 }
357 memset(&fl4, 0, sizeof(fl4)); 359 memset(&fl4, 0, sizeof(fl4));
358 fl4.daddr = daddr; 360 fl4.daddr = daddr;
359 fl4.saddr = rt->rt_spec_dst; 361 fl4.saddr = saddr;
360 fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); 362 fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos);
361 fl4.flowi4_proto = IPPROTO_ICMP; 363 fl4.flowi4_proto = IPPROTO_ICMP;
362 security_skb_classify_flow(skb, flowi4_to_flowi(&fl4)); 364 security_skb_classify_flow(skb, flowi4_to_flowi(&fl4));
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 708b99494e23..766dfe56885a 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -27,6 +27,7 @@
27#include <net/icmp.h> 27#include <net/icmp.h>
28#include <net/route.h> 28#include <net/route.h>
29#include <net/cipso_ipv4.h> 29#include <net/cipso_ipv4.h>
30#include <net/ip_fib.h>
30 31
31/* 32/*
32 * Write options to IP header, record destination address to 33 * Write options to IP header, record destination address to
@@ -104,7 +105,7 @@ int ip_options_echo(struct ip_options *dopt, struct sk_buff *skb)
104 sptr = skb_network_header(skb); 105 sptr = skb_network_header(skb);
105 dptr = dopt->__data; 106 dptr = dopt->__data;
106 107
107 daddr = skb_rtable(skb)->rt_spec_dst; 108 daddr = fib_compute_spec_dst(skb);
108 109
109 if (sopt->rr) { 110 if (sopt->rr) {
110 optlen = sptr[sopt->rr+1]; 111 optlen = sptr[sopt->rr+1];
@@ -250,15 +251,14 @@ void ip_options_fragment(struct sk_buff *skb)
250int ip_options_compile(struct net *net, 251int ip_options_compile(struct net *net,
251 struct ip_options *opt, struct sk_buff *skb) 252 struct ip_options *opt, struct sk_buff *skb)
252{ 253{
253 int l; 254 __be32 spec_dst = (__force __be32) 0;
254 unsigned char *iph;
255 unsigned char *optptr;
256 int optlen;
257 unsigned char *pp_ptr = NULL; 255 unsigned char *pp_ptr = NULL;
258 struct rtable *rt = NULL; 256 unsigned char *optptr;
257 unsigned char *iph;
258 int optlen, l;
259 259
260 if (skb != NULL) { 260 if (skb != NULL) {
261 rt = skb_rtable(skb); 261 spec_dst = fib_compute_spec_dst(skb);
262 optptr = (unsigned char *)&(ip_hdr(skb)[1]); 262 optptr = (unsigned char *)&(ip_hdr(skb)[1]);
263 } else 263 } else
264 optptr = opt->__data; 264 optptr = opt->__data;
@@ -330,8 +330,8 @@ int ip_options_compile(struct net *net,
330 pp_ptr = optptr + 2; 330 pp_ptr = optptr + 2;
331 goto error; 331 goto error;
332 } 332 }
333 if (rt) { 333 if (skb) {
334 memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); 334 memcpy(&optptr[optptr[2]-1], &spec_dst, 4);
335 opt->is_changed = 1; 335 opt->is_changed = 1;
336 } 336 }
337 optptr[2] += 4; 337 optptr[2] += 4;
@@ -372,8 +372,8 @@ int ip_options_compile(struct net *net,
372 goto error; 372 goto error;
373 } 373 }
374 opt->ts = optptr - iph; 374 opt->ts = optptr - iph;
375 if (rt) { 375 if (skb) {
376 memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); 376 memcpy(&optptr[optptr[2]-1], &spec_dst, 4);
377 timeptr = &optptr[optptr[2]+3]; 377 timeptr = &optptr[optptr[2]+3];
378 } 378 }
379 opt->ts_needaddr = 1; 379 opt->ts_needaddr = 1;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 0d11f234d615..de29f46f68b0 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -40,6 +40,7 @@
40#if IS_ENABLED(CONFIG_IPV6) 40#if IS_ENABLED(CONFIG_IPV6)
41#include <net/transp_v6.h> 41#include <net/transp_v6.h>
42#endif 42#endif
43#include <net/ip_fib.h>
43 44
44#include <linux/errqueue.h> 45#include <linux/errqueue.h>
45#include <asm/uaccess.h> 46#include <asm/uaccess.h>
@@ -1019,8 +1020,8 @@ e_inval:
1019 * @sk: socket 1020 * @sk: socket
1020 * @skb: buffer 1021 * @skb: buffer
1021 * 1022 *
1022 * To support IP_CMSG_PKTINFO option, we store rt_iif and rt_spec_dst 1023 * To support IP_CMSG_PKTINFO option, we store rt_iif and specific
1023 * in skb->cb[] before dst drop. 1024 * destination in skb->cb[] before dst drop.
1024 * This way, receiver doesnt make cache line misses to read rtable. 1025 * This way, receiver doesnt make cache line misses to read rtable.
1025 */ 1026 */
1026void ipv4_pktinfo_prepare(struct sk_buff *skb) 1027void ipv4_pktinfo_prepare(struct sk_buff *skb)
@@ -1030,7 +1031,7 @@ void ipv4_pktinfo_prepare(struct sk_buff *skb)
1030 1031
1031 if (rt) { 1032 if (rt) {
1032 pktinfo->ipi_ifindex = rt->rt_iif; 1033 pktinfo->ipi_ifindex = rt->rt_iif;
1033 pktinfo->ipi_spec_dst.s_addr = rt->rt_spec_dst; 1034 pktinfo->ipi_spec_dst.s_addr = fib_compute_spec_dst(skb);
1034 } else { 1035 } else {
1035 pktinfo->ipi_ifindex = 0; 1036 pktinfo->ipi_ifindex = 0;
1036 pktinfo->ipi_spec_dst.s_addr = 0; 1037 pktinfo->ipi_spec_dst.s_addr = 0;