diff options
Diffstat (limited to 'net/ipv4/xfrm4_mode_tunnel.c')
-rw-r--r-- | net/ipv4/xfrm4_mode_tunnel.c | 57 |
1 files changed, 46 insertions, 11 deletions
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index e23c21d31a53..e54c5494c88f 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
@@ -23,6 +23,12 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb) | |||
23 | IP_ECN_set_ce(inner_iph); | 23 | IP_ECN_set_ce(inner_iph); |
24 | } | 24 | } |
25 | 25 | ||
26 | static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) | ||
27 | { | ||
28 | if (INET_ECN_is_ce(iph->tos)) | ||
29 | IP6_ECN_set_ce(skb->nh.ipv6h); | ||
30 | } | ||
31 | |||
26 | /* Add encapsulation header. | 32 | /* Add encapsulation header. |
27 | * | 33 | * |
28 | * The top IP header will be constructed per RFC 2401. The following fields | 34 | * The top IP header will be constructed per RFC 2401. The following fields |
@@ -36,6 +42,7 @@ static inline void ipip_ecn_decapsulate(struct sk_buff *skb) | |||
36 | static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | 42 | static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
37 | { | 43 | { |
38 | struct dst_entry *dst = skb->dst; | 44 | struct dst_entry *dst = skb->dst; |
45 | struct xfrm_dst *xdst = (struct xfrm_dst*)dst; | ||
39 | struct iphdr *iph, *top_iph; | 46 | struct iphdr *iph, *top_iph; |
40 | int flags; | 47 | int flags; |
41 | 48 | ||
@@ -48,15 +55,27 @@ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
48 | top_iph->ihl = 5; | 55 | top_iph->ihl = 5; |
49 | top_iph->version = 4; | 56 | top_iph->version = 4; |
50 | 57 | ||
58 | flags = x->props.flags; | ||
59 | |||
51 | /* DS disclosed */ | 60 | /* DS disclosed */ |
52 | top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); | 61 | if (xdst->route->ops->family == AF_INET) { |
62 | top_iph->protocol = IPPROTO_IPIP; | ||
63 | top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); | ||
64 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
65 | 0 : (iph->frag_off & htons(IP_DF)); | ||
66 | } | ||
67 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
68 | else { | ||
69 | struct ipv6hdr *ipv6h = (struct ipv6hdr*)iph; | ||
70 | top_iph->protocol = IPPROTO_IPV6; | ||
71 | top_iph->tos = INET_ECN_encapsulate(iph->tos, ipv6_get_dsfield(ipv6h)); | ||
72 | top_iph->frag_off = 0; | ||
73 | } | ||
74 | #endif | ||
53 | 75 | ||
54 | flags = x->props.flags; | ||
55 | if (flags & XFRM_STATE_NOECN) | 76 | if (flags & XFRM_STATE_NOECN) |
56 | IP_ECN_clear(top_iph); | 77 | IP_ECN_clear(top_iph); |
57 | 78 | ||
58 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
59 | 0 : (iph->frag_off & htons(IP_DF)); | ||
60 | if (!top_iph->frag_off) | 79 | if (!top_iph->frag_off) |
61 | __ip_select_ident(top_iph, dst->child, 0); | 80 | __ip_select_ident(top_iph, dst->child, 0); |
62 | 81 | ||
@@ -64,7 +83,6 @@ static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | |||
64 | 83 | ||
65 | top_iph->saddr = x->props.saddr.a4; | 84 | top_iph->saddr = x->props.saddr.a4; |
66 | top_iph->daddr = x->id.daddr.a4; | 85 | top_iph->daddr = x->id.daddr.a4; |
67 | top_iph->protocol = IPPROTO_IPIP; | ||
68 | 86 | ||
69 | memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); | 87 | memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); |
70 | return 0; | 88 | return 0; |
@@ -75,8 +93,16 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
75 | struct iphdr *iph = skb->nh.iph; | 93 | struct iphdr *iph = skb->nh.iph; |
76 | int err = -EINVAL; | 94 | int err = -EINVAL; |
77 | 95 | ||
78 | if (iph->protocol != IPPROTO_IPIP) | 96 | switch(iph->protocol){ |
79 | goto out; | 97 | case IPPROTO_IPIP: |
98 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
99 | case IPPROTO_IPV6: | ||
100 | break; | ||
101 | #endif | ||
102 | default: | ||
103 | goto out; | ||
104 | } | ||
105 | |||
80 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | 106 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) |
81 | goto out; | 107 | goto out; |
82 | 108 | ||
@@ -84,10 +110,19 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | |||
84 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | 110 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) |
85 | goto out; | 111 | goto out; |
86 | 112 | ||
87 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | 113 | if (iph->protocol == IPPROTO_IPIP) { |
88 | ipv4_copy_dscp(iph, skb->h.ipiph); | 114 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) |
89 | if (!(x->props.flags & XFRM_STATE_NOECN)) | 115 | ipv4_copy_dscp(iph, skb->h.ipiph); |
90 | ipip_ecn_decapsulate(skb); | 116 | if (!(x->props.flags & XFRM_STATE_NOECN)) |
117 | ipip_ecn_decapsulate(skb); | ||
118 | } | ||
119 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
120 | else { | ||
121 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
122 | ipip6_ecn_decapsulate(iph, skb); | ||
123 | skb->protocol = htons(ETH_P_IPV6); | ||
124 | } | ||
125 | #endif | ||
91 | skb->mac.raw = memmove(skb->data - skb->mac_len, | 126 | skb->mac.raw = memmove(skb->data - skb->mac_len, |
92 | skb->mac.raw, skb->mac_len); | 127 | skb->mac.raw, skb->mac_len); |
93 | skb->nh.raw = skb->data; | 128 | skb->nh.raw = skb->data; |