diff options
-rw-r--r-- | include/net/xfrm.h | 51 | ||||
-rw-r--r-- | net/ipv4/xfrm4_mode_beet.c | 15 | ||||
-rw-r--r-- | net/ipv4/xfrm4_mode_tunnel.c | 37 | ||||
-rw-r--r-- | net/ipv4/xfrm4_output.c | 41 | ||||
-rw-r--r-- | net/ipv4/xfrm4_state.c | 17 | ||||
-rw-r--r-- | net/ipv6/xfrm6_mode_beet.c | 28 | ||||
-rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 31 | ||||
-rw-r--r-- | net/ipv6/xfrm6_output.c | 39 | ||||
-rw-r--r-- | net/ipv6/xfrm6_state.c | 18 |
9 files changed, 193 insertions, 84 deletions
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index c9345fe3f8d2..138c1868be1d 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
@@ -257,6 +257,7 @@ extern int __xfrm_state_delete(struct xfrm_state *x); | |||
257 | 257 | ||
258 | struct xfrm_state_afinfo { | 258 | struct xfrm_state_afinfo { |
259 | unsigned int family; | 259 | unsigned int family; |
260 | unsigned int proto; | ||
260 | struct module *owner; | 261 | struct module *owner; |
261 | struct xfrm_type *type_map[IPPROTO_MAX]; | 262 | struct xfrm_type *type_map[IPPROTO_MAX]; |
262 | struct xfrm_mode *mode_map[XFRM_MODE_MAX]; | 263 | struct xfrm_mode *mode_map[XFRM_MODE_MAX]; |
@@ -267,6 +268,8 @@ struct xfrm_state_afinfo { | |||
267 | int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); | 268 | int (*tmpl_sort)(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n); |
268 | int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); | 269 | int (*state_sort)(struct xfrm_state **dst, struct xfrm_state **src, int n); |
269 | int (*output)(struct sk_buff *skb); | 270 | int (*output)(struct sk_buff *skb); |
271 | int (*extract_output)(struct xfrm_state *x, | ||
272 | struct sk_buff *skb); | ||
270 | }; | 273 | }; |
271 | 274 | ||
272 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); | 275 | extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); |
@@ -312,7 +315,18 @@ struct xfrm_mode { | |||
312 | * header. The value of the network header will always point | 315 | * header. The value of the network header will always point |
313 | * to the top IP header while skb->data will point to the payload. | 316 | * to the top IP header while skb->data will point to the payload. |
314 | */ | 317 | */ |
315 | int (*output)(struct xfrm_state *x,struct sk_buff *skb); | 318 | int (*output2)(struct xfrm_state *x,struct sk_buff *skb); |
319 | |||
320 | /* | ||
321 | * This is the actual output entry point. | ||
322 | * | ||
323 | * For transport mode and equivalent this would be identical to | ||
324 | * output2 (which does not need to be set). While tunnel mode | ||
325 | * and equivalent would set this to a tunnel encapsulation function | ||
326 | * (xfrm4_prepare_output or xfrm6_prepare_output) that would in turn | ||
327 | * call output2. | ||
328 | */ | ||
329 | int (*output)(struct xfrm_state *x, struct sk_buff *skb); | ||
316 | 330 | ||
317 | struct xfrm_state_afinfo *afinfo; | 331 | struct xfrm_state_afinfo *afinfo; |
318 | struct module *owner; | 332 | struct module *owner; |
@@ -454,6 +468,35 @@ struct xfrm_skb_cb { | |||
454 | 468 | ||
455 | #define XFRM_SKB_CB(__skb) ((struct xfrm_skb_cb *)&((__skb)->cb[0])) | 469 | #define XFRM_SKB_CB(__skb) ((struct xfrm_skb_cb *)&((__skb)->cb[0])) |
456 | 470 | ||
471 | /* | ||
472 | * This structure is used by the afinfo prepare_input/prepare_output functions | ||
473 | * to transmit header information to the mode input/output functions. | ||
474 | */ | ||
475 | struct xfrm_mode_skb_cb { | ||
476 | union { | ||
477 | struct inet_skb_parm h4; | ||
478 | struct inet6_skb_parm h6; | ||
479 | } header; | ||
480 | |||
481 | /* Copied from header for IPv4, always set to zero and DF for IPv6. */ | ||
482 | __be16 id; | ||
483 | __be16 frag_off; | ||
484 | |||
485 | /* TOS for IPv4, class for IPv6. */ | ||
486 | u8 tos; | ||
487 | |||
488 | /* TTL for IPv4, hop limitfor IPv6. */ | ||
489 | u8 ttl; | ||
490 | |||
491 | /* Protocol for IPv4, NH for IPv6. */ | ||
492 | u8 protocol; | ||
493 | |||
494 | /* Used by IPv6 only, zero for IPv4. */ | ||
495 | u8 flow_lbl[3]; | ||
496 | }; | ||
497 | |||
498 | #define XFRM_MODE_SKB_CB(__skb) ((struct xfrm_mode_skb_cb *)&((__skb)->cb[0])) | ||
499 | |||
457 | /* Audit Information */ | 500 | /* Audit Information */ |
458 | struct xfrm_audit | 501 | struct xfrm_audit |
459 | { | 502 | { |
@@ -1051,6 +1094,7 @@ extern void xfrm_replay_notify(struct xfrm_state *x, int event); | |||
1051 | extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); | 1094 | extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); |
1052 | extern int xfrm_init_state(struct xfrm_state *x); | 1095 | extern int xfrm_init_state(struct xfrm_state *x); |
1053 | extern int xfrm_output(struct sk_buff *skb); | 1096 | extern int xfrm_output(struct sk_buff *skb); |
1097 | extern int xfrm4_extract_header(struct sk_buff *skb); | ||
1054 | extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, | 1098 | extern int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, |
1055 | int encap_type); | 1099 | int encap_type); |
1056 | extern int xfrm4_rcv(struct sk_buff *skb); | 1100 | extern int xfrm4_rcv(struct sk_buff *skb); |
@@ -1060,9 +1104,12 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi) | |||
1060 | return xfrm4_rcv_encap(skb, nexthdr, spi, 0); | 1104 | return xfrm4_rcv_encap(skb, nexthdr, spi, 0); |
1061 | } | 1105 | } |
1062 | 1106 | ||
1107 | extern int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb); | ||
1108 | extern int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb); | ||
1063 | extern int xfrm4_output(struct sk_buff *skb); | 1109 | extern int xfrm4_output(struct sk_buff *skb); |
1064 | extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); | 1110 | extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); |
1065 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); | 1111 | extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); |
1112 | extern int xfrm6_extract_header(struct sk_buff *skb); | ||
1066 | extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); | 1113 | extern int xfrm6_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi); |
1067 | extern int xfrm6_rcv(struct sk_buff *skb); | 1114 | extern int xfrm6_rcv(struct sk_buff *skb); |
1068 | extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, | 1115 | extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, |
@@ -1072,6 +1119,8 @@ extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short | |||
1072 | extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); | 1119 | extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); |
1073 | extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); | 1120 | extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); |
1074 | extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); | 1121 | extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); |
1122 | extern int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb); | ||
1123 | extern int xfrm6_prepare_output(struct xfrm_state *x, struct sk_buff *skb); | ||
1075 | extern int xfrm6_output(struct sk_buff *skb); | 1124 | extern int xfrm6_output(struct sk_buff *skb); |
1076 | extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, | 1125 | extern int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb, |
1077 | u8 **prevhdr); | 1126 | u8 **prevhdr); |
diff --git a/net/ipv4/xfrm4_mode_beet.c b/net/ipv4/xfrm4_mode_beet.c index e42e122414be..94842adce144 100644 --- a/net/ipv4/xfrm4_mode_beet.c +++ b/net/ipv4/xfrm4_mode_beet.c | |||
@@ -43,7 +43,17 @@ static int xfrm4_beet_output(struct xfrm_state *x, struct sk_buff *skb) | |||
43 | ph = (struct ip_beet_phdr *)__skb_pull(skb, sizeof(*iph) - hdrlen); | 43 | ph = (struct ip_beet_phdr *)__skb_pull(skb, sizeof(*iph) - hdrlen); |
44 | 44 | ||
45 | top_iph = ip_hdr(skb); | 45 | top_iph = ip_hdr(skb); |
46 | memmove(top_iph, iph, sizeof(*iph)); | 46 | |
47 | top_iph->ihl = 5; | ||
48 | top_iph->version = 4; | ||
49 | |||
50 | top_iph->protocol = XFRM_MODE_SKB_CB(skb)->protocol; | ||
51 | top_iph->tos = XFRM_MODE_SKB_CB(skb)->tos; | ||
52 | |||
53 | top_iph->id = XFRM_MODE_SKB_CB(skb)->id; | ||
54 | top_iph->frag_off = XFRM_MODE_SKB_CB(skb)->frag_off; | ||
55 | top_iph->ttl = XFRM_MODE_SKB_CB(skb)->ttl; | ||
56 | |||
47 | if (unlikely(optlen)) { | 57 | if (unlikely(optlen)) { |
48 | BUG_ON(optlen < 0); | 58 | BUG_ON(optlen < 0); |
49 | 59 | ||
@@ -111,7 +121,8 @@ out: | |||
111 | 121 | ||
112 | static struct xfrm_mode xfrm4_beet_mode = { | 122 | static struct xfrm_mode xfrm4_beet_mode = { |
113 | .input = xfrm4_beet_input, | 123 | .input = xfrm4_beet_input, |
114 | .output = xfrm4_beet_output, | 124 | .output2 = xfrm4_beet_output, |
125 | .output = xfrm4_prepare_output, | ||
115 | .owner = THIS_MODULE, | 126 | .owner = THIS_MODULE, |
116 | .encap = XFRM_MODE_BEET, | 127 | .encap = XFRM_MODE_BEET, |
117 | .flags = XFRM_MODE_FLAG_TUNNEL, | 128 | .flags = XFRM_MODE_FLAG_TUNNEL, |
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index 68a9f56ff09f..cc8bbb274e37 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
@@ -36,53 +36,37 @@ static inline void ipip6_ecn_decapsulate(struct iphdr *iph, struct sk_buff *skb) | |||
36 | static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | 36 | static int xfrm4_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) |
37 | { | 37 | { |
38 | struct dst_entry *dst = skb->dst; | 38 | struct dst_entry *dst = skb->dst; |
39 | struct xfrm_dst *xdst = (struct xfrm_dst*)dst; | 39 | struct iphdr *top_iph; |
40 | struct iphdr *iph, *top_iph; | ||
41 | int flags; | 40 | int flags; |
42 | 41 | ||
43 | iph = ip_hdr(skb); | ||
44 | |||
45 | skb_set_network_header(skb, -x->props.header_len); | 42 | skb_set_network_header(skb, -x->props.header_len); |
46 | skb->mac_header = skb->network_header + | 43 | skb->mac_header = skb->network_header + |
47 | offsetof(struct iphdr, protocol); | 44 | offsetof(struct iphdr, protocol); |
48 | skb->transport_header = skb->network_header + sizeof(*iph); | 45 | skb->transport_header = skb->network_header + sizeof(*top_iph); |
49 | top_iph = ip_hdr(skb); | 46 | top_iph = ip_hdr(skb); |
50 | 47 | ||
51 | top_iph->ihl = 5; | 48 | top_iph->ihl = 5; |
52 | top_iph->version = 4; | 49 | top_iph->version = 4; |
53 | 50 | ||
54 | flags = x->props.flags; | 51 | top_iph->protocol = x->inner_mode->afinfo->proto; |
55 | 52 | ||
56 | /* DS disclosed */ | 53 | /* DS disclosed */ |
57 | if (xdst->route->ops->family == AF_INET) { | 54 | top_iph->tos = INET_ECN_encapsulate(XFRM_MODE_SKB_CB(skb)->tos, |
58 | top_iph->protocol = IPPROTO_IPIP; | 55 | XFRM_MODE_SKB_CB(skb)->tos); |
59 | top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); | ||
60 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
61 | 0 : (iph->frag_off & htons(IP_DF)); | ||
62 | } | ||
63 | #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) | ||
64 | else { | ||
65 | struct ipv6hdr *ipv6h = (struct ipv6hdr*)iph; | ||
66 | top_iph->protocol = IPPROTO_IPV6; | ||
67 | top_iph->tos = INET_ECN_encapsulate(iph->tos, ipv6_get_dsfield(ipv6h)); | ||
68 | top_iph->frag_off = 0; | ||
69 | } | ||
70 | #endif | ||
71 | 56 | ||
57 | flags = x->props.flags; | ||
72 | if (flags & XFRM_STATE_NOECN) | 58 | if (flags & XFRM_STATE_NOECN) |
73 | IP_ECN_clear(top_iph); | 59 | IP_ECN_clear(top_iph); |
74 | 60 | ||
75 | if (!top_iph->frag_off) | 61 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? |
76 | __ip_select_ident(top_iph, dst->child, 0); | 62 | 0 : XFRM_MODE_SKB_CB(skb)->frag_off; |
63 | ip_select_ident(top_iph, dst->child, NULL); | ||
77 | 64 | ||
78 | top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); | 65 | top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); |
79 | 66 | ||
80 | top_iph->saddr = x->props.saddr.a4; | 67 | top_iph->saddr = x->props.saddr.a4; |
81 | top_iph->daddr = x->id.daddr.a4; | 68 | top_iph->daddr = x->id.daddr.a4; |
82 | 69 | ||
83 | skb->protocol = htons(ETH_P_IP); | ||
84 | |||
85 | memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); | ||
86 | return 0; | 70 | return 0; |
87 | } | 71 | } |
88 | 72 | ||
@@ -136,7 +120,8 @@ out: | |||
136 | 120 | ||
137 | static struct xfrm_mode xfrm4_tunnel_mode = { | 121 | static struct xfrm_mode xfrm4_tunnel_mode = { |
138 | .input = xfrm4_tunnel_input, | 122 | .input = xfrm4_tunnel_input, |
139 | .output = xfrm4_tunnel_output, | 123 | .output2 = xfrm4_tunnel_output, |
124 | .output = xfrm4_prepare_output, | ||
140 | .owner = THIS_MODULE, | 125 | .owner = THIS_MODULE, |
141 | .encap = XFRM_MODE_TUNNEL, | 126 | .encap = XFRM_MODE_TUNNEL, |
142 | .flags = XFRM_MODE_FLAG_TUNNEL, | 127 | .flags = XFRM_MODE_FLAG_TUNNEL, |
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index c4a7156962bd..13fd11335e28 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
@@ -8,11 +8,12 @@ | |||
8 | * 2 of the License, or (at your option) any later version. | 8 | * 2 of the License, or (at your option) any later version. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #include <linux/compiler.h> | ||
12 | #include <linux/if_ether.h> | 11 | #include <linux/if_ether.h> |
13 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | ||
14 | #include <linux/skbuff.h> | 14 | #include <linux/skbuff.h> |
15 | #include <linux/netfilter_ipv4.h> | 15 | #include <linux/netfilter_ipv4.h> |
16 | #include <net/dst.h> | ||
16 | #include <net/ip.h> | 17 | #include <net/ip.h> |
17 | #include <net/xfrm.h> | 18 | #include <net/xfrm.h> |
18 | #include <net/icmp.h> | 19 | #include <net/icmp.h> |
@@ -25,8 +26,6 @@ static int xfrm4_tunnel_check_size(struct sk_buff *skb) | |||
25 | if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) | 26 | if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) |
26 | goto out; | 27 | goto out; |
27 | 28 | ||
28 | IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; | ||
29 | |||
30 | if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df) | 29 | if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df) |
31 | goto out; | 30 | goto out; |
32 | 31 | ||
@@ -40,19 +39,39 @@ out: | |||
40 | return ret; | 39 | return ret; |
41 | } | 40 | } |
42 | 41 | ||
42 | int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb) | ||
43 | { | ||
44 | int err; | ||
45 | |||
46 | err = xfrm4_tunnel_check_size(skb); | ||
47 | if (err) | ||
48 | return err; | ||
49 | |||
50 | return xfrm4_extract_header(skb); | ||
51 | } | ||
52 | |||
53 | int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb) | ||
54 | { | ||
55 | int err; | ||
56 | |||
57 | err = x->inner_mode->afinfo->extract_output(x, skb); | ||
58 | if (err) | ||
59 | return err; | ||
60 | |||
61 | memset(IPCB(skb), 0, sizeof(*IPCB(skb))); | ||
62 | IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE; | ||
63 | |||
64 | skb->protocol = htons(ETH_P_IP); | ||
65 | |||
66 | return x->outer_mode->output2(x, skb); | ||
67 | } | ||
68 | EXPORT_SYMBOL(xfrm4_prepare_output); | ||
69 | |||
43 | static inline int xfrm4_output_one(struct sk_buff *skb) | 70 | static inline int xfrm4_output_one(struct sk_buff *skb) |
44 | { | 71 | { |
45 | struct dst_entry *dst = skb->dst; | ||
46 | struct xfrm_state *x = dst->xfrm; | ||
47 | struct iphdr *iph; | 72 | struct iphdr *iph; |
48 | int err; | 73 | int err; |
49 | 74 | ||
50 | if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) { | ||
51 | err = xfrm4_tunnel_check_size(skb); | ||
52 | if (err) | ||
53 | goto error_nolock; | ||
54 | } | ||
55 | |||
56 | err = xfrm_output(skb); | 75 | err = xfrm_output(skb); |
57 | if (err) | 76 | if (err) |
58 | goto error_nolock; | 77 | goto error_nolock; |
diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 13d54a1c3337..e6030e74ff65 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c | |||
@@ -47,12 +47,29 @@ __xfrm4_init_tempsel(struct xfrm_state *x, struct flowi *fl, | |||
47 | x->props.family = AF_INET; | 47 | x->props.family = AF_INET; |
48 | } | 48 | } |
49 | 49 | ||
50 | int xfrm4_extract_header(struct sk_buff *skb) | ||
51 | { | ||
52 | struct iphdr *iph = ip_hdr(skb); | ||
53 | |||
54 | XFRM_MODE_SKB_CB(skb)->id = iph->id; | ||
55 | XFRM_MODE_SKB_CB(skb)->frag_off = iph->frag_off; | ||
56 | XFRM_MODE_SKB_CB(skb)->tos = iph->tos; | ||
57 | XFRM_MODE_SKB_CB(skb)->ttl = iph->ttl; | ||
58 | XFRM_MODE_SKB_CB(skb)->protocol = iph->protocol; | ||
59 | memset(XFRM_MODE_SKB_CB(skb)->flow_lbl, 0, | ||
60 | sizeof(XFRM_MODE_SKB_CB(skb)->flow_lbl)); | ||
61 | |||
62 | return 0; | ||
63 | } | ||
64 | |||
50 | static struct xfrm_state_afinfo xfrm4_state_afinfo = { | 65 | static struct xfrm_state_afinfo xfrm4_state_afinfo = { |
51 | .family = AF_INET, | 66 | .family = AF_INET, |
67 | .proto = IPPROTO_IPIP, | ||
52 | .owner = THIS_MODULE, | 68 | .owner = THIS_MODULE, |
53 | .init_flags = xfrm4_init_flags, | 69 | .init_flags = xfrm4_init_flags, |
54 | .init_tempsel = __xfrm4_init_tempsel, | 70 | .init_tempsel = __xfrm4_init_tempsel, |
55 | .output = xfrm4_output, | 71 | .output = xfrm4_output, |
72 | .extract_output = xfrm4_extract_output, | ||
56 | }; | 73 | }; |
57 | 74 | ||
58 | void __init xfrm4_state_init(void) | 75 | void __init xfrm4_state_init(void) |
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 | */ |
26 | static int xfrm6_beet_output(struct xfrm_state *x, struct sk_buff *skb) | 26 | static 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 | ||
77 | static struct xfrm_mode xfrm6_beet_mode = { | 76 | static 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) | |||
38 | static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) | 38 | static 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 | ||
117 | static struct xfrm_mode xfrm6_tunnel_mode = { | 105 | static 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 | ||
48 | int 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 | |||
59 | int 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 | } | ||
73 | EXPORT_SYMBOL(xfrm6_prepare_output); | ||
74 | |||
46 | static inline int xfrm6_output_one(struct sk_buff *skb) | 75 | static 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 | ||
172 | int 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 | |||
171 | static struct xfrm_state_afinfo xfrm6_state_afinfo = { | 187 | static 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 | ||
180 | void __init xfrm6_state_init(void) | 198 | void __init xfrm6_state_init(void) |