aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/xfrm6_mode_beet.c28
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c31
-rw-r--r--net/ipv6/xfrm6_output.c39
-rw-r--r--net/ipv6/xfrm6_state.c18
4 files changed, 72 insertions, 44 deletions
diff --git a/net/ipv6/xfrm6_mode_beet.c b/net/ipv6/xfrm6_mode_beet.c
index 2bfb4f05c14c..4988ed9c76c6 100644
--- a/net/ipv6/xfrm6_mode_beet.c
+++ b/net/ipv6/xfrm6_mode_beet.c
@@ -25,25 +25,24 @@
25 */ 25 */
26static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) 26static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb)
27{ 27{
28 struct ipv6hdr *iph, *top_iph; 28 struct ipv6hdr *top_iph;
29 u8 *prevhdr;
30 int hdr_len;
31 29
32 iph = ipv6_hdr(skb);
33
34 hdr_len = ip6_find_1stfragopt(skb, &prevhdr);
35
36 skb_set_mac_header(skb, (prevhdr - x->props.header_len) - skb->data);
37 skb_set_network_header(skb, -x->props.header_len); 30 skb_set_network_header(skb, -x->props.header_len);
38 skb->transport_header = skb->network_header + hdr_len; 31 skb->mac_header = skb->network_header +
39 __skb_pull(skb, hdr_len); 32 offsetof(struct ipv6hdr, nexthdr);
40 33 skb->transport_header = skb->network_header + sizeof(*top_iph);
41 top_iph = ipv6_hdr(skb); 34 top_iph = ipv6_hdr(skb);
42 memmove(top_iph, iph, hdr_len);
43 35
36 top_iph->version = 6;
37
38 memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl,
39 sizeof(top_iph->flow_lbl));
40 top_iph->nexthdr = XFRM_MODE_SKB_CB(skb)->protocol;
41
42 ipv6_change_dsfield(top_iph, 0, XFRM_MODE_SKB_CB(skb)->tos);
43 top_iph->hop_limit = XFRM_MODE_SKB_CB(skb)->ttl;
44 ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); 44 ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
45 ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); 45 ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
46
47 return 0; 46 return 0;
48} 47}
49 48
@@ -76,7 +75,8 @@ out:
76 75
77static struct xfrm_mode xfrm6_beet_mode = { 76static struct xfrm_mode xfrm6_beet_mode = {
78 .input = xfrm6_beet_input, 77 .input = xfrm6_beet_input,
79 .output = xfrm6_beet_output, 78 .output2 = xfrm6_beet_output,
79 .output = xfrm6_prepare_output,
80 .owner = THIS_MODULE, 80 .owner = THIS_MODULE,
81 .encap = XFRM_MODE_BEET, 81 .encap = XFRM_MODE_BEET,
82 .flags = XFRM_MODE_FLAG_TUNNEL, 82 .flags = XFRM_MODE_FLAG_TUNNEL,
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c
index 9a43ea722481..d45ce5d44197 100644
--- a/net/ipv6/xfrm6_mode_tunnel.c
+++ b/net/ipv6/xfrm6_mode_tunnel.c
@@ -38,33 +38,22 @@ static inline void ip6ip_ecn_decapsulate(struct sk_buff *skb)
38static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) 38static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
39{ 39{
40 struct dst_entry *dst = skb->dst; 40 struct dst_entry *dst = skb->dst;
41 struct xfrm_dst *xdst = (struct xfrm_dst*)dst; 41 struct ipv6hdr *top_iph;
42 struct ipv6hdr *iph, *top_iph;
43 int dsfield; 42 int dsfield;
44 43
45 iph = ipv6_hdr(skb);
46
47 skb_set_network_header(skb, -x->props.header_len); 44 skb_set_network_header(skb, -x->props.header_len);
48 skb->mac_header = skb->network_header + 45 skb->mac_header = skb->network_header +
49 offsetof(struct ipv6hdr, nexthdr); 46 offsetof(struct ipv6hdr, nexthdr);
50 skb->transport_header = skb->network_header + sizeof(*iph); 47 skb->transport_header = skb->network_header + sizeof(*top_iph);
51 top_iph = ipv6_hdr(skb); 48 top_iph = ipv6_hdr(skb);
52 49
53 top_iph->version = 6; 50 top_iph->version = 6;
54 if (xdst->route->ops->family == AF_INET6) { 51
55 top_iph->priority = iph->priority; 52 memcpy(top_iph->flow_lbl, XFRM_MODE_SKB_CB(skb)->flow_lbl,
56 top_iph->flow_lbl[0] = iph->flow_lbl[0]; 53 sizeof(top_iph->flow_lbl));
57 top_iph->flow_lbl[1] = iph->flow_lbl[1]; 54 top_iph->nexthdr = x->inner_mode->afinfo->proto;
58 top_iph->flow_lbl[2] = iph->flow_lbl[2]; 55
59 top_iph->nexthdr = IPPROTO_IPV6; 56 dsfield = XFRM_MODE_SKB_CB(skb)->tos;
60 } else {
61 top_iph->priority = 0;
62 top_iph->flow_lbl[0] = 0;
63 top_iph->flow_lbl[1] = 0;
64 top_iph->flow_lbl[2] = 0;
65 top_iph->nexthdr = IPPROTO_IPIP;
66 }
67 dsfield = ipv6_get_dsfield(top_iph);
68 dsfield = INET_ECN_encapsulate(dsfield, dsfield); 57 dsfield = INET_ECN_encapsulate(dsfield, dsfield);
69 if (x->props.flags & XFRM_STATE_NOECN) 58 if (x->props.flags & XFRM_STATE_NOECN)
70 dsfield &= ~INET_ECN_MASK; 59 dsfield &= ~INET_ECN_MASK;
@@ -72,7 +61,6 @@ static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb)
72 top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); 61 top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
73 ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); 62 ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
74 ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); 63 ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
75 skb->protocol = htons(ETH_P_IPV6);
76 return 0; 64 return 0;
77} 65}
78 66
@@ -116,7 +104,8 @@ out:
116 104
117static struct xfrm_mode xfrm6_tunnel_mode = { 105static struct xfrm_mode xfrm6_tunnel_mode = {
118 .input = xfrm6_tunnel_input, 106 .input = xfrm6_tunnel_input,
119 .output = xfrm6_tunnel_output, 107 .output2 = xfrm6_tunnel_output,
108 .output = xfrm6_prepare_output,
120 .owner = THIS_MODULE, 109 .owner = THIS_MODULE,
121 .encap = XFRM_MODE_TUNNEL, 110 .encap = XFRM_MODE_TUNNEL,
122 .flags = XFRM_MODE_FLAG_TUNNEL, 111 .flags = XFRM_MODE_FLAG_TUNNEL,
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 656976760ad4..bc2e80e3b0b1 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -10,10 +10,12 @@
10 */ 10 */
11 11
12#include <linux/if_ether.h> 12#include <linux/if_ether.h>
13#include <linux/compiler.h> 13#include <linux/kernel.h>
14#include <linux/module.h>
14#include <linux/skbuff.h> 15#include <linux/skbuff.h>
15#include <linux/icmpv6.h> 16#include <linux/icmpv6.h>
16#include <linux/netfilter_ipv6.h> 17#include <linux/netfilter_ipv6.h>
18#include <net/dst.h>
17#include <net/ipv6.h> 19#include <net/ipv6.h>
18#include <net/xfrm.h> 20#include <net/xfrm.h>
19 21
@@ -43,19 +45,38 @@ static int xfrm6_tunnel_check_size(struct sk_buff *skb)
43 return ret; 45 return ret;
44} 46}
45 47
48int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb)
49{
50 int err;
51
52 err = xfrm6_tunnel_check_size(skb);
53 if (err)
54 return err;
55
56 return xfrm6_extract_header(skb);
57}
58
59int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
60{
61 int err;
62
63 err = x->inner_mode->afinfo->extract_output(x, skb);
64 if (err)
65 return err;
66
67 memset(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
68
69 skb->protocol = htons(ETH_P_IPV6);
70
71 return x->outer_mode->output2(x, skb);
72}
73EXPORT_SYMBOL(xfrm6_prepare_output);
74
46static inline int xfrm6_output_one(struct sk_buff *skb) 75static inline int xfrm6_output_one(struct sk_buff *skb)
47{ 76{
48 struct dst_entry *dst = skb->dst;
49 struct xfrm_state *x = dst->xfrm;
50 struct ipv6hdr *iph; 77 struct ipv6hdr *iph;
51 int err; 78 int err;
52 79
53 if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
54 err = xfrm6_tunnel_check_size(skb);
55 if (err)
56 goto error_nolock;
57 }
58
59 err = xfrm_output(skb); 80 err = xfrm_output(skb);
60 if (err) 81 if (err)
61 goto error_nolock; 82 goto error_nolock;
diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
index b392bee396f1..98b05f472322 100644
--- a/net/ipv6/xfrm6_state.c
+++ b/net/ipv6/xfrm6_state.c
@@ -14,6 +14,7 @@
14#include <net/xfrm.h> 14#include <net/xfrm.h>
15#include <linux/pfkeyv2.h> 15#include <linux/pfkeyv2.h>
16#include <linux/ipsec.h> 16#include <linux/ipsec.h>
17#include <net/dsfield.h>
17#include <net/ipv6.h> 18#include <net/ipv6.h>
18#include <net/addrconf.h> 19#include <net/addrconf.h>
19 20
@@ -168,13 +169,30 @@ __xfrm6_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n)
168 return 0; 169 return 0;
169} 170}
170 171
172int xfrm6_extract_header(struct sk_buff *skb)
173{
174 struct ipv6hdr *iph = ipv6_hdr(skb);
175
176 XFRM_MODE_SKB_CB(skb)->id = 0;
177 XFRM_MODE_SKB_CB(skb)->frag_off = htons(IP_DF);
178 XFRM_MODE_SKB_CB(skb)->tos = ipv6_get_dsfield(iph);
179 XFRM_MODE_SKB_CB(skb)->ttl = iph->hop_limit;
180 XFRM_MODE_SKB_CB(skb)->protocol = iph->nexthdr;
181 memcpy(XFRM_MODE_SKB_CB(skb)->flow_lbl, iph->flow_lbl,
182 sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl));
183
184 return 0;
185}
186
171static struct xfrm_state_afinfo xfrm6_state_afinfo = { 187static struct xfrm_state_afinfo xfrm6_state_afinfo = {
172 .family = AF_INET6, 188 .family = AF_INET6,
189 .proto = IPPROTO_IPV6,
173 .owner = THIS_MODULE, 190 .owner = THIS_MODULE,
174 .init_tempsel = __xfrm6_init_tempsel, 191 .init_tempsel = __xfrm6_init_tempsel,
175 .tmpl_sort = __xfrm6_tmpl_sort, 192 .tmpl_sort = __xfrm6_tmpl_sort,
176 .state_sort = __xfrm6_state_sort, 193 .state_sort = __xfrm6_state_sort,
177 .output = xfrm6_output, 194 .output = xfrm6_output,
195 .extract_output = xfrm6_extract_output,
178}; 196};
179 197
180void __init xfrm6_state_init(void) 198void __init xfrm6_state_init(void)