aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/ip_options.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/ip_options.c')
-rw-r--r--net/ipv4/ip_options.c26
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 */
248static 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)
250int ip_options_compile(struct net *net, 260int 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;