diff options
Diffstat (limited to 'net/ipv4/ip_options.c')
-rw-r--r-- | net/ipv4/ip_options.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 708b99494e2..a19d6471a31 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]; |
@@ -241,6 +242,15 @@ void ip_options_fragment(struct sk_buff *skb) | |||
241 | opt->ts_needtime = 0; | 242 | opt->ts_needtime = 0; |
242 | } | 243 | } |
243 | 244 | ||
245 | /* helper used by ip_options_compile() to call fib_compute_spec_dst() | ||
246 | * at most one time. | ||
247 | */ | ||
248 | static void spec_dst_fill(__be32 *spec_dst, struct sk_buff *skb) | ||
249 | { | ||
250 | if (*spec_dst == htonl(INADDR_ANY)) | ||
251 | *spec_dst = fib_compute_spec_dst(skb); | ||
252 | } | ||
253 | |||
244 | /* | 254 | /* |
245 | * Verify options and fill pointers in struct options. | 255 | * Verify options and fill pointers in struct options. |
246 | * Caller should clear *opt, and set opt->data. | 256 | * Caller should clear *opt, and set opt->data. |
@@ -250,12 +260,12 @@ void ip_options_fragment(struct sk_buff *skb) | |||
250 | int ip_options_compile(struct net *net, | 260 | int ip_options_compile(struct net *net, |
251 | struct ip_options *opt, struct sk_buff *skb) | 261 | struct ip_options *opt, struct sk_buff *skb) |
252 | { | 262 | { |
253 | int l; | 263 | __be32 spec_dst = htonl(INADDR_ANY); |
254 | unsigned char *iph; | ||
255 | unsigned char *optptr; | ||
256 | int optlen; | ||
257 | unsigned char *pp_ptr = NULL; | 264 | unsigned char *pp_ptr = NULL; |
258 | struct rtable *rt = NULL; | 265 | struct rtable *rt = NULL; |
266 | unsigned char *optptr; | ||
267 | unsigned char *iph; | ||
268 | int optlen, l; | ||
259 | 269 | ||
260 | if (skb != NULL) { | 270 | if (skb != NULL) { |
261 | rt = skb_rtable(skb); | 271 | rt = skb_rtable(skb); |
@@ -331,7 +341,8 @@ int ip_options_compile(struct net *net, | |||
331 | goto error; | 341 | goto error; |
332 | } | 342 | } |
333 | if (rt) { | 343 | if (rt) { |
334 | memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); | 344 | spec_dst_fill(&spec_dst, skb); |
345 | memcpy(&optptr[optptr[2]-1], &spec_dst, 4); | ||
335 | opt->is_changed = 1; | 346 | opt->is_changed = 1; |
336 | } | 347 | } |
337 | optptr[2] += 4; | 348 | optptr[2] += 4; |
@@ -373,7 +384,8 @@ int ip_options_compile(struct net *net, | |||
373 | } | 384 | } |
374 | opt->ts = optptr - iph; | 385 | opt->ts = optptr - iph; |
375 | if (rt) { | 386 | if (rt) { |
376 | memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4); | 387 | spec_dst_fill(&spec_dst, skb); |
388 | memcpy(&optptr[optptr[2]-1], &spec_dst, 4); | ||
377 | timeptr = &optptr[optptr[2]+3]; | 389 | timeptr = &optptr[optptr[2]+3]; |
378 | } | 390 | } |
379 | opt->ts_needaddr = 1; | 391 | opt->ts_needaddr = 1; |