diff options
| -rw-r--r-- | include/linux/xfrm.h | 4 | ||||
| -rw-r--r-- | include/net/xfrm.h | 17 | ||||
| -rw-r--r-- | net/ipv4/Kconfig | 18 | ||||
| -rw-r--r-- | net/ipv4/Makefile | 2 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_input.c | 28 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_mode_transport.c | 69 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_mode_tunnel.c | 125 | ||||
| -rw-r--r-- | net/ipv4/xfrm4_output.c | 61 | ||||
| -rw-r--r-- | net/ipv6/Kconfig | 20 | ||||
| -rw-r--r-- | net/ipv6/Makefile | 2 | ||||
| -rw-r--r-- | net/ipv6/ip6_output.c | 2 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_input.c | 29 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_mode_transport.c | 73 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_mode_tunnel.c | 121 | ||||
| -rw-r--r-- | net/ipv6/xfrm6_output.c | 63 | ||||
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 83 | ||||
| -rw-r--r-- | net/xfrm/xfrm_state.c | 6 |
17 files changed, 553 insertions, 170 deletions
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 6b42cc474c01..46a15c7a1a13 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h | |||
| @@ -118,6 +118,10 @@ enum | |||
| 118 | XFRM_SHARE_UNIQUE /* Use once */ | 118 | XFRM_SHARE_UNIQUE /* Use once */ |
| 119 | }; | 119 | }; |
| 120 | 120 | ||
| 121 | #define XFRM_MODE_TRANSPORT 0 | ||
| 122 | #define XFRM_MODE_TUNNEL 1 | ||
| 123 | #define XFRM_MODE_MAX 2 | ||
| 124 | |||
| 121 | /* Netlink configuration messages. */ | 125 | /* Netlink configuration messages. */ |
| 122 | enum { | 126 | enum { |
| 123 | XFRM_MSG_BASE = 0x10, | 127 | XFRM_MSG_BASE = 0x10, |
diff --git a/include/net/xfrm.h b/include/net/xfrm.h index ed7c9747059d..ed5bb34f817f 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h | |||
| @@ -20,6 +20,8 @@ | |||
| 20 | #include <net/ip6_fib.h> | 20 | #include <net/ip6_fib.h> |
| 21 | 21 | ||
| 22 | #define XFRM_ALIGN8(len) (((len) + 7) & ~7) | 22 | #define XFRM_ALIGN8(len) (((len) + 7) & ~7) |
| 23 | #define MODULE_ALIAS_XFRM_MODE(family, encap) \ | ||
| 24 | MODULE_ALIAS("xfrm-mode-" __stringify(family) "-" __stringify(encap)) | ||
| 23 | 25 | ||
| 24 | extern struct sock *xfrm_nl; | 26 | extern struct sock *xfrm_nl; |
| 25 | extern u32 sysctl_xfrm_aevent_etime; | 27 | extern u32 sysctl_xfrm_aevent_etime; |
| @@ -164,6 +166,7 @@ struct xfrm_state | |||
| 164 | /* Reference to data common to all the instances of this | 166 | /* Reference to data common to all the instances of this |
| 165 | * transformer. */ | 167 | * transformer. */ |
| 166 | struct xfrm_type *type; | 168 | struct xfrm_type *type; |
| 169 | struct xfrm_mode *mode; | ||
| 167 | 170 | ||
| 168 | /* Security context */ | 171 | /* Security context */ |
| 169 | struct xfrm_sec_ctx *security; | 172 | struct xfrm_sec_ctx *security; |
| @@ -205,6 +208,7 @@ struct xfrm_dst; | |||
| 205 | struct xfrm_policy_afinfo { | 208 | struct xfrm_policy_afinfo { |
| 206 | unsigned short family; | 209 | unsigned short family; |
| 207 | struct xfrm_type *type_map[256]; | 210 | struct xfrm_type *type_map[256]; |
| 211 | struct xfrm_mode *mode_map[XFRM_MODE_MAX]; | ||
| 208 | struct dst_ops *dst_ops; | 212 | struct dst_ops *dst_ops; |
| 209 | void (*garbage_collect)(void); | 213 | void (*garbage_collect)(void); |
| 210 | int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); | 214 | int (*dst_lookup)(struct xfrm_dst **dst, struct flowi *fl); |
| @@ -267,6 +271,19 @@ extern int xfrm_unregister_type(struct xfrm_type *type, unsigned short family); | |||
| 267 | extern struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family); | 271 | extern struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family); |
| 268 | extern void xfrm_put_type(struct xfrm_type *type); | 272 | extern void xfrm_put_type(struct xfrm_type *type); |
| 269 | 273 | ||
| 274 | struct xfrm_mode { | ||
| 275 | int (*input)(struct xfrm_state *x, struct sk_buff *skb); | ||
| 276 | int (*output)(struct sk_buff *skb); | ||
| 277 | |||
| 278 | struct module *owner; | ||
| 279 | unsigned int encap; | ||
| 280 | }; | ||
| 281 | |||
| 282 | extern int xfrm_register_mode(struct xfrm_mode *mode, int family); | ||
| 283 | extern int xfrm_unregister_mode(struct xfrm_mode *mode, int family); | ||
| 284 | extern struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family); | ||
| 285 | extern void xfrm_put_mode(struct xfrm_mode *mode); | ||
| 286 | |||
| 270 | struct xfrm_tmpl | 287 | struct xfrm_tmpl |
| 271 | { | 288 | { |
| 272 | /* id in template is interpreted as: | 289 | /* id in template is interpreted as: |
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index e40f75322377..35eb70b1448d 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig | |||
| @@ -414,6 +414,24 @@ config INET_TUNNEL | |||
| 414 | tristate | 414 | tristate |
| 415 | default n | 415 | default n |
| 416 | 416 | ||
| 417 | config INET_XFRM_MODE_TRANSPORT | ||
| 418 | tristate "IP: IPsec transport mode" | ||
| 419 | default y | ||
| 420 | select XFRM | ||
| 421 | ---help--- | ||
| 422 | Support for IPsec transport mode. | ||
| 423 | |||
| 424 | If unsure, say Y. | ||
| 425 | |||
| 426 | config INET_XFRM_MODE_TUNNEL | ||
| 427 | tristate "IP: IPsec tunnel mode" | ||
| 428 | default y | ||
| 429 | select XFRM | ||
| 430 | ---help--- | ||
| 431 | Support for IPsec tunnel mode. | ||
| 432 | |||
| 433 | If unsure, say Y. | ||
| 434 | |||
| 417 | config INET_DIAG | 435 | config INET_DIAG |
| 418 | tristate "INET: socket monitoring interface" | 436 | tristate "INET: socket monitoring interface" |
| 419 | default y | 437 | default y |
diff --git a/net/ipv4/Makefile b/net/ipv4/Makefile index 9ef50a0b9d2c..4cc94482eacc 100644 --- a/net/ipv4/Makefile +++ b/net/ipv4/Makefile | |||
| @@ -24,6 +24,8 @@ obj-$(CONFIG_INET_ESP) += esp4.o | |||
| 24 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o | 24 | obj-$(CONFIG_INET_IPCOMP) += ipcomp.o |
| 25 | obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o | 25 | obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o |
| 26 | obj-$(CONFIG_INET_TUNNEL) += tunnel4.o | 26 | obj-$(CONFIG_INET_TUNNEL) += tunnel4.o |
| 27 | obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o | ||
| 28 | obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o | ||
| 27 | obj-$(CONFIG_IP_PNP) += ipconfig.o | 29 | obj-$(CONFIG_IP_PNP) += ipconfig.o |
| 28 | obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o | 30 | obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o |
| 29 | obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o | 31 | obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o |
diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 3e174c83bfe7..817ed84511a6 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | #include <linux/string.h> | 13 | #include <linux/string.h> |
| 14 | #include <linux/netfilter.h> | 14 | #include <linux/netfilter.h> |
| 15 | #include <linux/netfilter_ipv4.h> | 15 | #include <linux/netfilter_ipv4.h> |
| 16 | #include <net/inet_ecn.h> | ||
| 17 | #include <net/ip.h> | 16 | #include <net/ip.h> |
| 18 | #include <net/xfrm.h> | 17 | #include <net/xfrm.h> |
| 19 | 18 | ||
| @@ -24,15 +23,6 @@ int xfrm4_rcv(struct sk_buff *skb) | |||
| 24 | 23 | ||
| 25 | EXPORT_SYMBOL(xfrm4_rcv); | 24 | EXPORT_SYMBOL(xfrm4_rcv); |
| 26 | 25 | ||
| 27 | static inline void ipip_ecn_decapsulate(struct sk_buff *skb) | ||
| 28 | { | ||
| 29 | struct iphdr *outer_iph = skb->nh.iph; | ||
| 30 | struct iphdr *inner_iph = skb->h.ipiph; | ||
| 31 | |||
| 32 | if (INET_ECN_is_ce(outer_iph->tos)) | ||
| 33 | IP_ECN_set_ce(inner_iph); | ||
| 34 | } | ||
| 35 | |||
| 36 | static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) | 26 | static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) |
| 37 | { | 27 | { |
| 38 | switch (nexthdr) { | 28 | switch (nexthdr) { |
| @@ -113,24 +103,10 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) | |||
| 113 | 103 | ||
| 114 | xfrm_vec[xfrm_nr++] = x; | 104 | xfrm_vec[xfrm_nr++] = x; |
| 115 | 105 | ||
| 116 | iph = skb->nh.iph; | 106 | if (x->mode->input(x, skb)) |
| 107 | goto drop; | ||
| 117 | 108 | ||
| 118 | if (x->props.mode) { | 109 | if (x->props.mode) { |
| 119 | if (iph->protocol != IPPROTO_IPIP) | ||
| 120 | goto drop; | ||
| 121 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | ||
| 122 | goto drop; | ||
| 123 | if (skb_cloned(skb) && | ||
| 124 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | ||
| 125 | goto drop; | ||
| 126 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
| 127 | ipv4_copy_dscp(iph, skb->h.ipiph); | ||
| 128 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
| 129 | ipip_ecn_decapsulate(skb); | ||
| 130 | skb->mac.raw = memmove(skb->data - skb->mac_len, | ||
| 131 | skb->mac.raw, skb->mac_len); | ||
| 132 | skb->nh.raw = skb->data; | ||
| 133 | memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); | ||
| 134 | decaps = 1; | 110 | decaps = 1; |
| 135 | break; | 111 | break; |
| 136 | } | 112 | } |
diff --git a/net/ipv4/xfrm4_mode_transport.c b/net/ipv4/xfrm4_mode_transport.c new file mode 100644 index 000000000000..e46d9a4ccc55 --- /dev/null +++ b/net/ipv4/xfrm4_mode_transport.c | |||
| @@ -0,0 +1,69 @@ | |||
| 1 | /* | ||
| 2 | * xfrm4_mode_transport.c - Transport mode encapsulation for IPv4. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/init.h> | ||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/skbuff.h> | ||
| 11 | #include <linux/stringify.h> | ||
| 12 | #include <net/dst.h> | ||
| 13 | #include <net/ip.h> | ||
| 14 | #include <net/xfrm.h> | ||
| 15 | |||
| 16 | /* Add encapsulation header. | ||
| 17 | * | ||
| 18 | * The IP header will be moved forward to make space for the encapsulation | ||
| 19 | * header. | ||
| 20 | * | ||
| 21 | * On exit, skb->h will be set to the start of the payload to be processed | ||
| 22 | * by x->type->output and skb->nh will be set to the top IP header. | ||
| 23 | */ | ||
| 24 | static int xfrm4_transport_output(struct sk_buff *skb) | ||
| 25 | { | ||
| 26 | struct xfrm_state *x; | ||
| 27 | struct iphdr *iph; | ||
| 28 | int ihl; | ||
| 29 | |||
| 30 | iph = skb->nh.iph; | ||
| 31 | skb->h.ipiph = iph; | ||
| 32 | |||
| 33 | ihl = iph->ihl * 4; | ||
| 34 | skb->h.raw += ihl; | ||
| 35 | |||
| 36 | x = skb->dst->xfrm; | ||
| 37 | skb->nh.raw = memmove(skb_push(skb, x->props.header_len), iph, ihl); | ||
| 38 | return 0; | ||
| 39 | } | ||
| 40 | |||
| 41 | static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 42 | { | ||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | static struct xfrm_mode xfrm4_transport_mode = { | ||
| 47 | .input = xfrm4_transport_input, | ||
| 48 | .output = xfrm4_transport_output, | ||
| 49 | .owner = THIS_MODULE, | ||
| 50 | .encap = XFRM_MODE_TRANSPORT, | ||
| 51 | }; | ||
| 52 | |||
| 53 | static int __init xfrm4_transport_init(void) | ||
| 54 | { | ||
| 55 | return xfrm_register_mode(&xfrm4_transport_mode, AF_INET); | ||
| 56 | } | ||
| 57 | |||
| 58 | static void __exit xfrm4_transport_exit(void) | ||
| 59 | { | ||
| 60 | int err; | ||
| 61 | |||
| 62 | err = xfrm_unregister_mode(&xfrm4_transport_mode, AF_INET); | ||
| 63 | BUG_ON(err); | ||
| 64 | } | ||
| 65 | |||
| 66 | module_init(xfrm4_transport_init); | ||
| 67 | module_exit(xfrm4_transport_exit); | ||
| 68 | MODULE_LICENSE("GPL"); | ||
| 69 | MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TRANSPORT); | ||
diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c new file mode 100644 index 000000000000..f8d880beb12f --- /dev/null +++ b/net/ipv4/xfrm4_mode_tunnel.c | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | /* | ||
| 2 | * xfrm4_mode_tunnel.c - Tunnel mode encapsulation for IPv4. | ||
| 3 | * | ||
| 4 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 5 | */ | ||
| 6 | |||
| 7 | #include <linux/init.h> | ||
| 8 | #include <linux/kernel.h> | ||
| 9 | #include <linux/module.h> | ||
| 10 | #include <linux/skbuff.h> | ||
| 11 | #include <linux/stringify.h> | ||
| 12 | #include <net/dst.h> | ||
| 13 | #include <net/inet_ecn.h> | ||
| 14 | #include <net/ip.h> | ||
| 15 | #include <net/xfrm.h> | ||
| 16 | |||
| 17 | static inline void ipip_ecn_decapsulate(struct sk_buff *skb) | ||
| 18 | { | ||
| 19 | struct iphdr *outer_iph = skb->nh.iph; | ||
| 20 | struct iphdr *inner_iph = skb->h.ipiph; | ||
| 21 | |||
| 22 | if (INET_ECN_is_ce(outer_iph->tos)) | ||
| 23 | IP_ECN_set_ce(inner_iph); | ||
| 24 | } | ||
| 25 | |||
| 26 | /* Add encapsulation header. | ||
| 27 | * | ||
| 28 | * The top IP header will be constructed per RFC 2401. The following fields | ||
| 29 | * in it shall be filled in by x->type->output: | ||
| 30 | * tot_len | ||
| 31 | * check | ||
| 32 | * | ||
| 33 | * On exit, skb->h will be set to the start of the payload to be processed | ||
| 34 | * by x->type->output and skb->nh will be set to the top IP header. | ||
| 35 | */ | ||
| 36 | static int xfrm4_tunnel_output(struct sk_buff *skb) | ||
| 37 | { | ||
| 38 | struct dst_entry *dst = skb->dst; | ||
| 39 | struct xfrm_state *x = dst->xfrm; | ||
| 40 | struct iphdr *iph, *top_iph; | ||
| 41 | int flags; | ||
| 42 | |||
| 43 | iph = skb->nh.iph; | ||
| 44 | skb->h.ipiph = iph; | ||
| 45 | |||
| 46 | skb->nh.raw = skb_push(skb, x->props.header_len); | ||
| 47 | top_iph = skb->nh.iph; | ||
| 48 | |||
| 49 | top_iph->ihl = 5; | ||
| 50 | top_iph->version = 4; | ||
| 51 | |||
| 52 | /* DS disclosed */ | ||
| 53 | top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); | ||
| 54 | |||
| 55 | flags = x->props.flags; | ||
| 56 | if (flags & XFRM_STATE_NOECN) | ||
| 57 | IP_ECN_clear(top_iph); | ||
| 58 | |||
| 59 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
| 60 | 0 : (iph->frag_off & htons(IP_DF)); | ||
| 61 | if (!top_iph->frag_off) | ||
| 62 | __ip_select_ident(top_iph, dst->child, 0); | ||
| 63 | |||
| 64 | top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); | ||
| 65 | |||
| 66 | top_iph->saddr = x->props.saddr.a4; | ||
| 67 | top_iph->daddr = x->id.daddr.a4; | ||
| 68 | top_iph->protocol = IPPROTO_IPIP; | ||
| 69 | |||
| 70 | memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 75 | { | ||
| 76 | struct iphdr *iph = skb->nh.iph; | ||
| 77 | int err = -EINVAL; | ||
| 78 | |||
| 79 | if (iph->protocol != IPPROTO_IPIP) | ||
| 80 | goto out; | ||
| 81 | if (!pskb_may_pull(skb, sizeof(struct iphdr))) | ||
| 82 | goto out; | ||
| 83 | |||
| 84 | if (skb_cloned(skb) && | ||
| 85 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | ||
| 86 | goto out; | ||
| 87 | |||
| 88 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
| 89 | ipv4_copy_dscp(iph, skb->h.ipiph); | ||
| 90 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
| 91 | ipip_ecn_decapsulate(skb); | ||
| 92 | skb->mac.raw = memmove(skb->data - skb->mac_len, | ||
| 93 | skb->mac.raw, skb->mac_len); | ||
| 94 | skb->nh.raw = skb->data; | ||
| 95 | memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); | ||
| 96 | err = 0; | ||
| 97 | |||
| 98 | out: | ||
| 99 | return err; | ||
| 100 | } | ||
| 101 | |||
| 102 | static struct xfrm_mode xfrm4_tunnel_mode = { | ||
| 103 | .input = xfrm4_tunnel_input, | ||
| 104 | .output = xfrm4_tunnel_output, | ||
| 105 | .owner = THIS_MODULE, | ||
| 106 | .encap = XFRM_MODE_TUNNEL, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static int __init xfrm4_tunnel_init(void) | ||
| 110 | { | ||
| 111 | return xfrm_register_mode(&xfrm4_tunnel_mode, AF_INET); | ||
| 112 | } | ||
| 113 | |||
| 114 | static void __exit xfrm4_tunnel_exit(void) | ||
| 115 | { | ||
| 116 | int err; | ||
| 117 | |||
| 118 | err = xfrm_unregister_mode(&xfrm4_tunnel_mode, AF_INET); | ||
| 119 | BUG_ON(err); | ||
| 120 | } | ||
| 121 | |||
| 122 | module_init(xfrm4_tunnel_init); | ||
| 123 | module_exit(xfrm4_tunnel_exit); | ||
| 124 | MODULE_LICENSE("GPL"); | ||
| 125 | MODULE_ALIAS_XFRM_MODE(AF_INET, XFRM_MODE_TUNNEL); | ||
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 4ef8efaf6a67..ac9d91d4bb05 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c | |||
| @@ -12,67 +12,10 @@ | |||
| 12 | #include <linux/skbuff.h> | 12 | #include <linux/skbuff.h> |
| 13 | #include <linux/spinlock.h> | 13 | #include <linux/spinlock.h> |
| 14 | #include <linux/netfilter_ipv4.h> | 14 | #include <linux/netfilter_ipv4.h> |
| 15 | #include <net/inet_ecn.h> | ||
| 16 | #include <net/ip.h> | 15 | #include <net/ip.h> |
| 17 | #include <net/xfrm.h> | 16 | #include <net/xfrm.h> |
| 18 | #include <net/icmp.h> | 17 | #include <net/icmp.h> |
| 19 | 18 | ||
| 20 | /* Add encapsulation header. | ||
| 21 | * | ||
| 22 | * In transport mode, the IP header will be moved forward to make space | ||
| 23 | * for the encapsulation header. | ||
| 24 | * | ||
| 25 | * In tunnel mode, the top IP header will be constructed per RFC 2401. | ||
| 26 | * The following fields in it shall be filled in by x->type->output: | ||
| 27 | * tot_len | ||
| 28 | * check | ||
| 29 | * | ||
| 30 | * On exit, skb->h will be set to the start of the payload to be processed | ||
| 31 | * by x->type->output and skb->nh will be set to the top IP header. | ||
| 32 | */ | ||
| 33 | static void xfrm4_encap(struct sk_buff *skb) | ||
| 34 | { | ||
| 35 | struct dst_entry *dst = skb->dst; | ||
| 36 | struct xfrm_state *x = dst->xfrm; | ||
| 37 | struct iphdr *iph, *top_iph; | ||
| 38 | int flags; | ||
| 39 | |||
| 40 | iph = skb->nh.iph; | ||
| 41 | skb->h.ipiph = iph; | ||
| 42 | |||
| 43 | skb->nh.raw = skb_push(skb, x->props.header_len); | ||
| 44 | top_iph = skb->nh.iph; | ||
| 45 | |||
| 46 | if (!x->props.mode) { | ||
| 47 | skb->h.raw += iph->ihl*4; | ||
| 48 | memmove(top_iph, iph, iph->ihl*4); | ||
| 49 | return; | ||
| 50 | } | ||
| 51 | |||
| 52 | top_iph->ihl = 5; | ||
| 53 | top_iph->version = 4; | ||
| 54 | |||
| 55 | /* DS disclosed */ | ||
| 56 | top_iph->tos = INET_ECN_encapsulate(iph->tos, iph->tos); | ||
| 57 | |||
| 58 | flags = x->props.flags; | ||
| 59 | if (flags & XFRM_STATE_NOECN) | ||
| 60 | IP_ECN_clear(top_iph); | ||
| 61 | |||
| 62 | top_iph->frag_off = (flags & XFRM_STATE_NOPMTUDISC) ? | ||
| 63 | 0 : (iph->frag_off & htons(IP_DF)); | ||
| 64 | if (!top_iph->frag_off) | ||
| 65 | __ip_select_ident(top_iph, dst->child, 0); | ||
| 66 | |||
| 67 | top_iph->ttl = dst_metric(dst->child, RTAX_HOPLIMIT); | ||
| 68 | |||
| 69 | top_iph->saddr = x->props.saddr.a4; | ||
| 70 | top_iph->daddr = x->id.daddr.a4; | ||
| 71 | top_iph->protocol = IPPROTO_IPIP; | ||
| 72 | |||
| 73 | memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); | ||
| 74 | } | ||
| 75 | |||
| 76 | static int xfrm4_tunnel_check_size(struct sk_buff *skb) | 19 | static int xfrm4_tunnel_check_size(struct sk_buff *skb) |
| 77 | { | 20 | { |
| 78 | int mtu, ret = 0; | 21 | int mtu, ret = 0; |
| @@ -121,7 +64,9 @@ static int xfrm4_output_one(struct sk_buff *skb) | |||
| 121 | if (err) | 64 | if (err) |
| 122 | goto error; | 65 | goto error; |
| 123 | 66 | ||
| 124 | xfrm4_encap(skb); | 67 | err = x->mode->output(skb); |
| 68 | if (err) | ||
| 69 | goto error; | ||
| 125 | 70 | ||
| 126 | err = x->type->output(x, skb); | 71 | err = x->type->output(x, skb); |
| 127 | if (err) | 72 | if (err) |
diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index f8a107ab5592..e923d4dea418 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig | |||
| @@ -106,6 +106,26 @@ config INET6_TUNNEL | |||
| 106 | tristate | 106 | tristate |
| 107 | default n | 107 | default n |
| 108 | 108 | ||
| 109 | config INET6_XFRM_MODE_TRANSPORT | ||
| 110 | tristate "IPv6: IPsec transport mode" | ||
| 111 | depends on IPV6 | ||
| 112 | default IPV6 | ||
| 113 | select XFRM | ||
| 114 | ---help--- | ||
| 115 | Support for IPsec transport mode. | ||
| 116 | |||
| 117 | If unsure, say Y. | ||
| 118 | |||
| 119 | config INET6_XFRM_MODE_TUNNEL | ||
| 120 | tristate "IPv6: IPsec tunnel mode" | ||
| 121 | depends on IPV6 | ||
| 122 | default IPV6 | ||
| 123 | select XFRM | ||
| 124 | ---help--- | ||
| 125 | Support for IPsec tunnel mode. | ||
| 126 | |||
| 127 | If unsure, say Y. | ||
| 128 | |||
| 109 | config IPV6_TUNNEL | 129 | config IPV6_TUNNEL |
| 110 | tristate "IPv6: IPv6-in-IPv6 tunnel" | 130 | tristate "IPv6: IPv6-in-IPv6 tunnel" |
| 111 | select INET6_TUNNEL | 131 | select INET6_TUNNEL |
diff --git a/net/ipv6/Makefile b/net/ipv6/Makefile index a760b0988fbb..386e0a626948 100644 --- a/net/ipv6/Makefile +++ b/net/ipv6/Makefile | |||
| @@ -20,6 +20,8 @@ obj-$(CONFIG_INET6_ESP) += esp6.o | |||
| 20 | obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o | 20 | obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o |
| 21 | obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o | 21 | obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o |
| 22 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o | 22 | obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o |
| 23 | obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o | ||
| 24 | obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o | ||
| 23 | obj-$(CONFIG_NETFILTER) += netfilter/ | 25 | obj-$(CONFIG_NETFILTER) += netfilter/ |
| 24 | 26 | ||
| 25 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o | 27 | obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o |
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index e46048974f37..416f6e428a0a 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c | |||
| @@ -39,6 +39,7 @@ | |||
| 39 | #include <linux/in6.h> | 39 | #include <linux/in6.h> |
| 40 | #include <linux/tcp.h> | 40 | #include <linux/tcp.h> |
| 41 | #include <linux/route.h> | 41 | #include <linux/route.h> |
| 42 | #include <linux/module.h> | ||
| 42 | 43 | ||
| 43 | #include <linux/netfilter.h> | 44 | #include <linux/netfilter.h> |
| 44 | #include <linux/netfilter_ipv6.h> | 45 | #include <linux/netfilter_ipv6.h> |
| @@ -488,6 +489,7 @@ int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) | |||
| 488 | 489 | ||
| 489 | return offset; | 490 | return offset; |
| 490 | } | 491 | } |
| 492 | EXPORT_SYMBOL_GPL(ip6_find_1stfragopt); | ||
| 491 | 493 | ||
| 492 | static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) | 494 | static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) |
| 493 | { | 495 | { |
diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 00cfdee18dca..0405d74ff910 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c | |||
| @@ -13,21 +13,9 @@ | |||
| 13 | #include <linux/string.h> | 13 | #include <linux/string.h> |
| 14 | #include <linux/netfilter.h> | 14 | #include <linux/netfilter.h> |
| 15 | #include <linux/netfilter_ipv6.h> | 15 | #include <linux/netfilter_ipv6.h> |
| 16 | #include <net/dsfield.h> | ||
| 17 | #include <net/inet_ecn.h> | ||
| 18 | #include <net/ip.h> | ||
| 19 | #include <net/ipv6.h> | 16 | #include <net/ipv6.h> |
| 20 | #include <net/xfrm.h> | 17 | #include <net/xfrm.h> |
| 21 | 18 | ||
| 22 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | ||
| 23 | { | ||
| 24 | struct ipv6hdr *outer_iph = skb->nh.ipv6h; | ||
| 25 | struct ipv6hdr *inner_iph = skb->h.ipv6h; | ||
| 26 | |||
| 27 | if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) | ||
| 28 | IP6_ECN_set_ce(inner_iph); | ||
| 29 | } | ||
| 30 | |||
| 31 | int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) | 19 | int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) |
| 32 | { | 20 | { |
| 33 | int err; | 21 | int err; |
| @@ -81,21 +69,10 @@ int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) | |||
| 81 | 69 | ||
| 82 | xfrm_vec[xfrm_nr++] = x; | 70 | xfrm_vec[xfrm_nr++] = x; |
| 83 | 71 | ||
| 72 | if (x->mode->input(x, skb)) | ||
| 73 | goto drop; | ||
| 74 | |||
| 84 | if (x->props.mode) { /* XXX */ | 75 | if (x->props.mode) { /* XXX */ |
| 85 | if (nexthdr != IPPROTO_IPV6) | ||
| 86 | goto drop; | ||
| 87 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
| 88 | goto drop; | ||
| 89 | if (skb_cloned(skb) && | ||
| 90 | pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) | ||
| 91 | goto drop; | ||
| 92 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
| 93 | ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h); | ||
| 94 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
| 95 | ipip6_ecn_decapsulate(skb); | ||
| 96 | skb->mac.raw = memmove(skb->data - skb->mac_len, | ||
| 97 | skb->mac.raw, skb->mac_len); | ||
| 98 | skb->nh.raw = skb->data; | ||
| 99 | decaps = 1; | 76 | decaps = 1; |
| 100 | break; | 77 | break; |
| 101 | } | 78 | } |
diff --git a/net/ipv6/xfrm6_mode_transport.c b/net/ipv6/xfrm6_mode_transport.c new file mode 100644 index 000000000000..5efbbae08ef0 --- /dev/null +++ b/net/ipv6/xfrm6_mode_transport.c | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | /* | ||
| 2 | * xfrm6_mode_transport.c - Transport mode encapsulation for IPv6. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 USAGI/WIDE Project | ||
| 5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/init.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/skbuff.h> | ||
| 12 | #include <linux/stringify.h> | ||
| 13 | #include <net/dst.h> | ||
| 14 | #include <net/ipv6.h> | ||
| 15 | #include <net/xfrm.h> | ||
| 16 | |||
| 17 | /* Add encapsulation header. | ||
| 18 | * | ||
| 19 | * The IP header and mutable extension headers will be moved forward to make | ||
| 20 | * space for the encapsulation header. | ||
| 21 | * | ||
| 22 | * On exit, skb->h will be set to the start of the encapsulation header to be | ||
| 23 | * filled in by x->type->output and skb->nh will be set to the nextheader field | ||
| 24 | * of the extension header directly preceding the encapsulation header, or in | ||
| 25 | * its absence, that of the top IP header. The value of skb->data will always | ||
| 26 | * point to the top IP header. | ||
| 27 | */ | ||
| 28 | static int xfrm6_transport_output(struct sk_buff *skb) | ||
| 29 | { | ||
| 30 | struct xfrm_state *x = skb->dst->xfrm; | ||
| 31 | struct ipv6hdr *iph; | ||
| 32 | u8 *prevhdr; | ||
| 33 | int hdr_len; | ||
| 34 | |||
| 35 | skb_push(skb, x->props.header_len); | ||
| 36 | iph = skb->nh.ipv6h; | ||
| 37 | |||
| 38 | hdr_len = ip6_find_1stfragopt(skb, &prevhdr); | ||
| 39 | skb->nh.raw = prevhdr - x->props.header_len; | ||
| 40 | skb->h.raw = skb->data + hdr_len; | ||
| 41 | memmove(skb->data, iph, hdr_len); | ||
| 42 | return 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 46 | { | ||
| 47 | return 0; | ||
| 48 | } | ||
| 49 | |||
| 50 | static struct xfrm_mode xfrm6_transport_mode = { | ||
| 51 | .input = xfrm6_transport_input, | ||
| 52 | .output = xfrm6_transport_output, | ||
| 53 | .owner = THIS_MODULE, | ||
| 54 | .encap = XFRM_MODE_TRANSPORT, | ||
| 55 | }; | ||
| 56 | |||
| 57 | static int __init xfrm6_transport_init(void) | ||
| 58 | { | ||
| 59 | return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6); | ||
| 60 | } | ||
| 61 | |||
| 62 | static void __exit xfrm6_transport_exit(void) | ||
| 63 | { | ||
| 64 | int err; | ||
| 65 | |||
| 66 | err = xfrm_unregister_mode(&xfrm6_transport_mode, AF_INET6); | ||
| 67 | BUG_ON(err); | ||
| 68 | } | ||
| 69 | |||
| 70 | module_init(xfrm6_transport_init); | ||
| 71 | module_exit(xfrm6_transport_exit); | ||
| 72 | MODULE_LICENSE("GPL"); | ||
| 73 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TRANSPORT); | ||
diff --git a/net/ipv6/xfrm6_mode_tunnel.c b/net/ipv6/xfrm6_mode_tunnel.c new file mode 100644 index 000000000000..8af79be2edca --- /dev/null +++ b/net/ipv6/xfrm6_mode_tunnel.c | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | /* | ||
| 2 | * xfrm6_mode_tunnel.c - Tunnel mode encapsulation for IPv6. | ||
| 3 | * | ||
| 4 | * Copyright (C) 2002 USAGI/WIDE Project | ||
| 5 | * Copyright (c) 2004-2006 Herbert Xu <herbert@gondor.apana.org.au> | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include <linux/init.h> | ||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/module.h> | ||
| 11 | #include <linux/skbuff.h> | ||
| 12 | #include <linux/stringify.h> | ||
| 13 | #include <net/dsfield.h> | ||
| 14 | #include <net/dst.h> | ||
| 15 | #include <net/inet_ecn.h> | ||
| 16 | #include <net/ipv6.h> | ||
| 17 | #include <net/xfrm.h> | ||
| 18 | |||
| 19 | static inline void ipip6_ecn_decapsulate(struct sk_buff *skb) | ||
| 20 | { | ||
| 21 | struct ipv6hdr *outer_iph = skb->nh.ipv6h; | ||
| 22 | struct ipv6hdr *inner_iph = skb->h.ipv6h; | ||
| 23 | |||
| 24 | if (INET_ECN_is_ce(ipv6_get_dsfield(outer_iph))) | ||
| 25 | IP6_ECN_set_ce(inner_iph); | ||
| 26 | } | ||
| 27 | |||
| 28 | /* Add encapsulation header. | ||
| 29 | * | ||
| 30 | * The top IP header will be constructed per RFC 2401. The following fields | ||
| 31 | * in it shall be filled in by x->type->output: | ||
| 32 | * payload_len | ||
| 33 | * | ||
| 34 | * On exit, skb->h will be set to the start of the encapsulation header to be | ||
| 35 | * filled in by x->type->output and skb->nh will be set to the nextheader field | ||
| 36 | * of the extension header directly preceding the encapsulation header, or in | ||
| 37 | * its absence, that of the top IP header. The value of skb->data will always | ||
| 38 | * point to the top IP header. | ||
| 39 | */ | ||
| 40 | static int xfrm6_tunnel_output(struct sk_buff *skb) | ||
| 41 | { | ||
| 42 | struct dst_entry *dst = skb->dst; | ||
| 43 | struct xfrm_state *x = dst->xfrm; | ||
| 44 | struct ipv6hdr *iph, *top_iph; | ||
| 45 | int dsfield; | ||
| 46 | |||
| 47 | skb_push(skb, x->props.header_len); | ||
| 48 | iph = skb->nh.ipv6h; | ||
| 49 | |||
| 50 | skb->nh.raw = skb->data; | ||
| 51 | top_iph = skb->nh.ipv6h; | ||
| 52 | skb->nh.raw = &top_iph->nexthdr; | ||
| 53 | skb->h.ipv6h = top_iph + 1; | ||
| 54 | |||
| 55 | top_iph->version = 6; | ||
| 56 | top_iph->priority = iph->priority; | ||
| 57 | top_iph->flow_lbl[0] = iph->flow_lbl[0]; | ||
| 58 | top_iph->flow_lbl[1] = iph->flow_lbl[1]; | ||
| 59 | top_iph->flow_lbl[2] = iph->flow_lbl[2]; | ||
| 60 | dsfield = ipv6_get_dsfield(top_iph); | ||
| 61 | dsfield = INET_ECN_encapsulate(dsfield, dsfield); | ||
| 62 | if (x->props.flags & XFRM_STATE_NOECN) | ||
| 63 | dsfield &= ~INET_ECN_MASK; | ||
| 64 | ipv6_change_dsfield(top_iph, 0, dsfield); | ||
| 65 | top_iph->nexthdr = IPPROTO_IPV6; | ||
| 66 | top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); | ||
| 67 | ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); | ||
| 68 | ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); | ||
| 69 | return 0; | ||
| 70 | } | ||
| 71 | |||
| 72 | static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) | ||
| 73 | { | ||
| 74 | int err = -EINVAL; | ||
| 75 | |||
| 76 | if (skb->nh.raw[IP6CB(skb)->nhoff] != IPPROTO_IPV6) | ||
| 77 | goto out; | ||
| 78 | if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) | ||
| 79 | goto out; | ||
| 80 | |||
| 81 | if (skb_cloned(skb) && | ||
| 82 | (err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC))) | ||
| 83 | goto out; | ||
| 84 | |||
| 85 | if (x->props.flags & XFRM_STATE_DECAP_DSCP) | ||
| 86 | ipv6_copy_dscp(skb->nh.ipv6h, skb->h.ipv6h); | ||
| 87 | if (!(x->props.flags & XFRM_STATE_NOECN)) | ||
| 88 | ipip6_ecn_decapsulate(skb); | ||
| 89 | skb->mac.raw = memmove(skb->data - skb->mac_len, | ||
| 90 | skb->mac.raw, skb->mac_len); | ||
| 91 | skb->nh.raw = skb->data; | ||
| 92 | err = 0; | ||
| 93 | |||
| 94 | out: | ||
| 95 | return err; | ||
| 96 | } | ||
| 97 | |||
| 98 | static struct xfrm_mode xfrm6_tunnel_mode = { | ||
| 99 | .input = xfrm6_tunnel_input, | ||
| 100 | .output = xfrm6_tunnel_output, | ||
| 101 | .owner = THIS_MODULE, | ||
| 102 | .encap = XFRM_MODE_TUNNEL, | ||
| 103 | }; | ||
| 104 | |||
| 105 | static int __init xfrm6_tunnel_init(void) | ||
| 106 | { | ||
| 107 | return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6); | ||
| 108 | } | ||
| 109 | |||
| 110 | static void __exit xfrm6_tunnel_exit(void) | ||
| 111 | { | ||
| 112 | int err; | ||
| 113 | |||
| 114 | err = xfrm_unregister_mode(&xfrm6_tunnel_mode, AF_INET6); | ||
| 115 | BUG_ON(err); | ||
| 116 | } | ||
| 117 | |||
| 118 | module_init(xfrm6_tunnel_init); | ||
| 119 | module_exit(xfrm6_tunnel_exit); | ||
| 120 | MODULE_LICENSE("GPL"); | ||
| 121 | MODULE_ALIAS_XFRM_MODE(AF_INET6, XFRM_MODE_TUNNEL); | ||
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c index 80242172a5df..16e84254a252 100644 --- a/net/ipv6/xfrm6_output.c +++ b/net/ipv6/xfrm6_output.c | |||
| @@ -14,68 +14,9 @@ | |||
| 14 | #include <linux/spinlock.h> | 14 | #include <linux/spinlock.h> |
| 15 | #include <linux/icmpv6.h> | 15 | #include <linux/icmpv6.h> |
| 16 | #include <linux/netfilter_ipv6.h> | 16 | #include <linux/netfilter_ipv6.h> |
| 17 | #include <net/dsfield.h> | ||
| 18 | #include <net/inet_ecn.h> | ||
| 19 | #include <net/ipv6.h> | 17 | #include <net/ipv6.h> |
| 20 | #include <net/xfrm.h> | 18 | #include <net/xfrm.h> |
| 21 | 19 | ||
| 22 | /* Add encapsulation header. | ||
| 23 | * | ||
| 24 | * In transport mode, the IP header and mutable extension headers will be moved | ||
| 25 | * forward to make space for the encapsulation header. | ||
| 26 | * | ||
| 27 | * In tunnel mode, the top IP header will be constructed per RFC 2401. | ||
| 28 | * The following fields in it shall be filled in by x->type->output: | ||
| 29 | * payload_len | ||
| 30 | * | ||
| 31 | * On exit, skb->h will be set to the start of the encapsulation header to be | ||
| 32 | * filled in by x->type->output and skb->nh will be set to the nextheader field | ||
| 33 | * of the extension header directly preceding the encapsulation header, or in | ||
| 34 | * its absence, that of the top IP header. The value of skb->data will always | ||
| 35 | * point to the top IP header. | ||
| 36 | */ | ||
| 37 | static void xfrm6_encap(struct sk_buff *skb) | ||
| 38 | { | ||
| 39 | struct dst_entry *dst = skb->dst; | ||
| 40 | struct xfrm_state *x = dst->xfrm; | ||
| 41 | struct ipv6hdr *iph, *top_iph; | ||
| 42 | int dsfield; | ||
| 43 | |||
| 44 | skb_push(skb, x->props.header_len); | ||
| 45 | iph = skb->nh.ipv6h; | ||
| 46 | |||
| 47 | if (!x->props.mode) { | ||
| 48 | u8 *prevhdr; | ||
| 49 | int hdr_len; | ||
| 50 | |||
| 51 | hdr_len = ip6_find_1stfragopt(skb, &prevhdr); | ||
| 52 | skb->nh.raw = prevhdr - x->props.header_len; | ||
| 53 | skb->h.raw = skb->data + hdr_len; | ||
| 54 | memmove(skb->data, iph, hdr_len); | ||
| 55 | return; | ||
| 56 | } | ||
| 57 | |||
| 58 | skb->nh.raw = skb->data; | ||
| 59 | top_iph = skb->nh.ipv6h; | ||
| 60 | skb->nh.raw = &top_iph->nexthdr; | ||
| 61 | skb->h.ipv6h = top_iph + 1; | ||
| 62 | |||
| 63 | top_iph->version = 6; | ||
| 64 | top_iph->priority = iph->priority; | ||
| 65 | top_iph->flow_lbl[0] = iph->flow_lbl[0]; | ||
| 66 | top_iph->flow_lbl[1] = iph->flow_lbl[1]; | ||
| 67 | top_iph->flow_lbl[2] = iph->flow_lbl[2]; | ||
| 68 | dsfield = ipv6_get_dsfield(top_iph); | ||
| 69 | dsfield = INET_ECN_encapsulate(dsfield, dsfield); | ||
| 70 | if (x->props.flags & XFRM_STATE_NOECN) | ||
| 71 | dsfield &= ~INET_ECN_MASK; | ||
| 72 | ipv6_change_dsfield(top_iph, 0, dsfield); | ||
| 73 | top_iph->nexthdr = IPPROTO_IPV6; | ||
| 74 | top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT); | ||
| 75 | ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr); | ||
| 76 | ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); | ||
| 77 | } | ||
| 78 | |||
| 79 | static int xfrm6_tunnel_check_size(struct sk_buff *skb) | 20 | static int xfrm6_tunnel_check_size(struct sk_buff *skb) |
| 80 | { | 21 | { |
| 81 | int mtu, ret = 0; | 22 | int mtu, ret = 0; |
| @@ -118,7 +59,9 @@ static int xfrm6_output_one(struct sk_buff *skb) | |||
| 118 | if (err) | 59 | if (err) |
| 119 | goto error; | 60 | goto error; |
| 120 | 61 | ||
| 121 | xfrm6_encap(skb); | 62 | err = x->mode->output(skb); |
| 63 | if (err) | ||
| 64 | goto error; | ||
| 122 | 65 | ||
| 123 | err = x->type->output(x, skb); | 66 | err = x->type->output(x, skb); |
| 124 | if (err) | 67 | if (err) |
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 44b64a593c01..b8936926c24b 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -138,6 +138,89 @@ void xfrm_put_type(struct xfrm_type *type) | |||
| 138 | module_put(type->owner); | 138 | module_put(type->owner); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | int xfrm_register_mode(struct xfrm_mode *mode, int family) | ||
| 142 | { | ||
| 143 | struct xfrm_policy_afinfo *afinfo; | ||
| 144 | struct xfrm_mode **modemap; | ||
| 145 | int err; | ||
| 146 | |||
| 147 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
| 148 | return -EINVAL; | ||
| 149 | |||
| 150 | afinfo = xfrm_policy_lock_afinfo(family); | ||
| 151 | if (unlikely(afinfo == NULL)) | ||
| 152 | return -EAFNOSUPPORT; | ||
| 153 | |||
| 154 | err = -EEXIST; | ||
| 155 | modemap = afinfo->mode_map; | ||
| 156 | if (likely(modemap[mode->encap] == NULL)) { | ||
| 157 | modemap[mode->encap] = mode; | ||
| 158 | err = 0; | ||
| 159 | } | ||
| 160 | |||
| 161 | xfrm_policy_unlock_afinfo(afinfo); | ||
| 162 | return err; | ||
| 163 | } | ||
| 164 | EXPORT_SYMBOL(xfrm_register_mode); | ||
| 165 | |||
| 166 | int xfrm_unregister_mode(struct xfrm_mode *mode, int family) | ||
| 167 | { | ||
| 168 | struct xfrm_policy_afinfo *afinfo; | ||
| 169 | struct xfrm_mode **modemap; | ||
| 170 | int err; | ||
| 171 | |||
| 172 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | ||
| 173 | return -EINVAL; | ||
| 174 | |||
| 175 | afinfo = xfrm_policy_lock_afinfo(family); | ||
| 176 | if (unlikely(afinfo == NULL)) | ||
| 177 | return -EAFNOSUPPORT; | ||
| 178 | |||
| 179 | err = -ENOENT; | ||
| 180 | modemap = afinfo->mode_map; | ||
| 181 | if (likely(modemap[mode->encap] == mode)) { | ||
| 182 | modemap[mode->encap] = NULL; | ||
| 183 | err = 0; | ||
| 184 | } | ||
| 185 | |||
| 186 | xfrm_policy_unlock_afinfo(afinfo); | ||
| 187 | return err; | ||
| 188 | } | ||
| 189 | EXPORT_SYMBOL(xfrm_unregister_mode); | ||
| 190 | |||
| 191 | struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family) | ||
| 192 | { | ||
| 193 | struct xfrm_policy_afinfo *afinfo; | ||
| 194 | struct xfrm_mode *mode; | ||
| 195 | int modload_attempted = 0; | ||
| 196 | |||
| 197 | if (unlikely(encap >= XFRM_MODE_MAX)) | ||
| 198 | return NULL; | ||
| 199 | |||
| 200 | retry: | ||
| 201 | afinfo = xfrm_policy_get_afinfo(family); | ||
| 202 | if (unlikely(afinfo == NULL)) | ||
| 203 | return NULL; | ||
| 204 | |||
| 205 | mode = afinfo->mode_map[encap]; | ||
| 206 | if (unlikely(mode && !try_module_get(mode->owner))) | ||
| 207 | mode = NULL; | ||
| 208 | if (!mode && !modload_attempted) { | ||
| 209 | xfrm_policy_put_afinfo(afinfo); | ||
| 210 | request_module("xfrm-mode-%d-%d", family, encap); | ||
| 211 | modload_attempted = 1; | ||
| 212 | goto retry; | ||
| 213 | } | ||
| 214 | |||
| 215 | xfrm_policy_put_afinfo(afinfo); | ||
| 216 | return mode; | ||
| 217 | } | ||
| 218 | |||
| 219 | void xfrm_put_mode(struct xfrm_mode *mode) | ||
| 220 | { | ||
| 221 | module_put(mode->owner); | ||
| 222 | } | ||
| 223 | |||
| 141 | static inline unsigned long make_jiffies(long secs) | 224 | static inline unsigned long make_jiffies(long secs) |
| 142 | { | 225 | { |
| 143 | if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) | 226 | if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) |
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index ee62c239a7e3..17b29ec3c417 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
| @@ -77,6 +77,8 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) | |||
| 77 | kfree(x->ealg); | 77 | kfree(x->ealg); |
| 78 | kfree(x->calg); | 78 | kfree(x->calg); |
| 79 | kfree(x->encap); | 79 | kfree(x->encap); |
| 80 | if (x->mode) | ||
| 81 | xfrm_put_mode(x->mode); | ||
| 80 | if (x->type) { | 82 | if (x->type) { |
| 81 | x->type->destructor(x); | 83 | x->type->destructor(x); |
| 82 | xfrm_put_type(x->type); | 84 | xfrm_put_type(x->type); |
| @@ -1193,6 +1195,10 @@ int xfrm_init_state(struct xfrm_state *x) | |||
| 1193 | if (err) | 1195 | if (err) |
| 1194 | goto error; | 1196 | goto error; |
| 1195 | 1197 | ||
| 1198 | x->mode = xfrm_get_mode(x->props.mode, family); | ||
| 1199 | if (x->mode == NULL) | ||
| 1200 | goto error; | ||
| 1201 | |||
| 1196 | x->km.state = XFRM_STATE_VALID; | 1202 | x->km.state = XFRM_STATE_VALID; |
| 1197 | 1203 | ||
| 1198 | error: | 1204 | error: |
