diff options
-rw-r--r-- | include/net/ip_fib.h | 1 | ||||
-rw-r--r-- | net/ipv4/fib_frontend.c | 29 | ||||
-rw-r--r-- | net/ipv4/icmp.c | 6 | ||||
-rw-r--r-- | net/ipv4/ip_options.c | 22 | ||||
-rw-r--r-- | net/ipv4/ip_sockglue.c | 7 |
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 */ |
231 | extern const struct nla_policy rtm_ipv4_policy[]; | 231 | extern const struct nla_policy rtm_ipv4_policy[]; |
232 | extern void ip_fib_init(void); | 232 | extern void ip_fib_init(void); |
233 | extern __be32 fib_compute_spec_dst(struct sk_buff *skb); | ||
233 | extern int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, | 234 | extern 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 | } |
181 | EXPORT_SYMBOL(inet_dev_addr_type); | 181 | EXPORT_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) | |||
250 | int ip_options_compile(struct net *net, | 251 | int 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 | */ |
1026 | void ipv4_pktinfo_prepare(struct sk_buff *skb) | 1027 | void 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; |