diff options
author | Li Wei <lw@cn.fujitsu.com> | 2011-11-22 18:33:10 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-11-23 19:19:32 -0500 |
commit | ac8a48106be49c422575ddc7531b776f8eb49610 (patch) | |
tree | d770975ffc9cebfcbb2d3ad40b0601a8d1e77c32 | |
parent | 67c170a24fc6669f8f7c0864d75caadef0a8e5e6 (diff) |
ipv4: Save nexthop address of LSRR/SSRR option to IPCB.
We can not update iph->daddr in ip_options_rcv_srr(), It is too early.
When some exception ocurred later (eg. in ip_forward() when goto
sr_failed) we need the ip header be identical to the original one as
ICMP need it.
Add a field 'nexthop' in struct ip_options to save nexthop of LSRR
or SSRR option.
Signed-off-by: Li Wei <lw@cn.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/inet_sock.h | 2 | ||||
-rw-r--r-- | net/ipv4/ip_forward.c | 2 | ||||
-rw-r--r-- | net/ipv4/ip_options.c | 5 |
3 files changed, 6 insertions, 3 deletions
diff --git a/include/net/inet_sock.h b/include/net/inet_sock.h index b897d6e6d0a5..f941964a9931 100644 --- a/include/net/inet_sock.h +++ b/include/net/inet_sock.h | |||
@@ -31,6 +31,7 @@ | |||
31 | /** struct ip_options - IP Options | 31 | /** struct ip_options - IP Options |
32 | * | 32 | * |
33 | * @faddr - Saved first hop address | 33 | * @faddr - Saved first hop address |
34 | * @nexthop - Saved nexthop address in LSRR and SSRR | ||
34 | * @is_data - Options in __data, rather than skb | 35 | * @is_data - Options in __data, rather than skb |
35 | * @is_strictroute - Strict source route | 36 | * @is_strictroute - Strict source route |
36 | * @srr_is_hit - Packet destination addr was our one | 37 | * @srr_is_hit - Packet destination addr was our one |
@@ -41,6 +42,7 @@ | |||
41 | */ | 42 | */ |
42 | struct ip_options { | 43 | struct ip_options { |
43 | __be32 faddr; | 44 | __be32 faddr; |
45 | __be32 nexthop; | ||
44 | unsigned char optlen; | 46 | unsigned char optlen; |
45 | unsigned char srr; | 47 | unsigned char srr; |
46 | unsigned char rr; | 48 | unsigned char rr; |
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 3b34d1c86270..29a07b6c7168 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c | |||
@@ -84,7 +84,7 @@ int ip_forward(struct sk_buff *skb) | |||
84 | 84 | ||
85 | rt = skb_rtable(skb); | 85 | rt = skb_rtable(skb); |
86 | 86 | ||
87 | if (opt->is_strictroute && ip_hdr(skb)->daddr != rt->rt_gateway) | 87 | if (opt->is_strictroute && opt->nexthop != rt->rt_gateway) |
88 | goto sr_failed; | 88 | goto sr_failed; |
89 | 89 | ||
90 | if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && | 90 | if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) && |
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 05d20cca9d66..1e60f7679075 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -568,12 +568,13 @@ void ip_forward_options(struct sk_buff *skb) | |||
568 | ) { | 568 | ) { |
569 | if (srrptr + 3 > srrspace) | 569 | if (srrptr + 3 > srrspace) |
570 | break; | 570 | break; |
571 | if (memcmp(&ip_hdr(skb)->daddr, &optptr[srrptr-1], 4) == 0) | 571 | if (memcmp(&opt->nexthop, &optptr[srrptr-1], 4) == 0) |
572 | break; | 572 | break; |
573 | } | 573 | } |
574 | if (srrptr + 3 <= srrspace) { | 574 | if (srrptr + 3 <= srrspace) { |
575 | opt->is_changed = 1; | 575 | opt->is_changed = 1; |
576 | ip_rt_get_source(&optptr[srrptr-1], skb, rt); | 576 | ip_rt_get_source(&optptr[srrptr-1], skb, rt); |
577 | ip_hdr(skb)->daddr = opt->nexthop; | ||
577 | optptr[2] = srrptr+4; | 578 | optptr[2] = srrptr+4; |
578 | } else if (net_ratelimit()) | 579 | } else if (net_ratelimit()) |
579 | printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); | 580 | printk(KERN_CRIT "ip_forward(): Argh! Destination lost!\n"); |
@@ -640,7 +641,7 @@ int ip_options_rcv_srr(struct sk_buff *skb) | |||
640 | } | 641 | } |
641 | if (srrptr <= srrspace) { | 642 | if (srrptr <= srrspace) { |
642 | opt->srr_is_hit = 1; | 643 | opt->srr_is_hit = 1; |
643 | iph->daddr = nexthop; | 644 | opt->nexthop = nexthop; |
644 | opt->is_changed = 1; | 645 | opt->is_changed = 1; |
645 | } | 646 | } |
646 | return 0; | 647 | return 0; |