aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-05-28 02:05:54 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2006-06-18 00:28:39 -0400
commitb59f45d0b2878ab76f8053b0973654e6621828ee (patch)
tree40dc5e2ede2620f7935fb3dae0d0eb199851f611 /net/ipv6
parent546be2405be119ef55467aace45f337a16e5d424 (diff)
[IPSEC] xfrm: Abstract out encapsulation modes
This patch adds the structure xfrm_mode. It is meant to represent the operations carried out by transport/tunnel modes. By doing this we allow additional encapsulation modes to be added without clogging up the xfrm_input/xfrm_output paths. Candidate modes include 4-to-6 tunnel mode, 6-to-4 tunnel mode, and BEET modes. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r--net/ipv6/Kconfig20
-rw-r--r--net/ipv6/Makefile2
-rw-r--r--net/ipv6/ip6_output.c2
-rw-r--r--net/ipv6/xfrm6_input.c29
-rw-r--r--net/ipv6/xfrm6_mode_transport.c73
-rw-r--r--net/ipv6/xfrm6_mode_tunnel.c121
-rw-r--r--net/ipv6/xfrm6_output.c63
7 files changed, 224 insertions, 86 deletions
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
109config 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
119config 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
109config IPV6_TUNNEL 129config 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
20obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o 20obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
21obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o 21obj-$(CONFIG_INET6_XFRM_TUNNEL) += xfrm6_tunnel.o
22obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o 22obj-$(CONFIG_INET6_TUNNEL) += tunnel6.o
23obj-$(CONFIG_INET6_XFRM_MODE_TRANSPORT) += xfrm6_mode_transport.o
24obj-$(CONFIG_INET6_XFRM_MODE_TUNNEL) += xfrm6_mode_tunnel.o
23obj-$(CONFIG_NETFILTER) += netfilter/ 25obj-$(CONFIG_NETFILTER) += netfilter/
24 26
25obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o 27obj-$(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}
492EXPORT_SYMBOL_GPL(ip6_find_1stfragopt);
491 493
492static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) 494static 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
22static 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
31int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi) 19int 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 */
28static 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
45static int xfrm6_transport_input(struct xfrm_state *x, struct sk_buff *skb)
46{
47 return 0;
48}
49
50static 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
57static int __init xfrm6_transport_init(void)
58{
59 return xfrm_register_mode(&xfrm6_transport_mode, AF_INET6);
60}
61
62static 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
70module_init(xfrm6_transport_init);
71module_exit(xfrm6_transport_exit);
72MODULE_LICENSE("GPL");
73MODULE_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
19static 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 */
40static 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
72static 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
94out:
95 return err;
96}
97
98static 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
105static int __init xfrm6_tunnel_init(void)
106{
107 return xfrm_register_mode(&xfrm6_tunnel_mode, AF_INET6);
108}
109
110static 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
118module_init(xfrm6_tunnel_init);
119module_exit(xfrm6_tunnel_exit);
120MODULE_LICENSE("GPL");
121MODULE_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 */
37static 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
79static int xfrm6_tunnel_check_size(struct sk_buff *skb) 20static 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)