aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
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/ipv4
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/ipv4')
-rw-r--r--net/ipv4/Kconfig18
-rw-r--r--net/ipv4/Makefile2
-rw-r--r--net/ipv4/xfrm4_input.c28
-rw-r--r--net/ipv4/xfrm4_mode_transport.c69
-rw-r--r--net/ipv4/xfrm4_mode_tunnel.c125
-rw-r--r--net/ipv4/xfrm4_output.c61
6 files changed, 219 insertions, 84 deletions
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
417config 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
426config 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
417config INET_DIAG 435config 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
24obj-$(CONFIG_INET_IPCOMP) += ipcomp.o 24obj-$(CONFIG_INET_IPCOMP) += ipcomp.o
25obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o 25obj-$(CONFIG_INET_XFRM_TUNNEL) += xfrm4_tunnel.o
26obj-$(CONFIG_INET_TUNNEL) += tunnel4.o 26obj-$(CONFIG_INET_TUNNEL) += tunnel4.o
27obj-$(CONFIG_INET_XFRM_MODE_TRANSPORT) += xfrm4_mode_transport.o
28obj-$(CONFIG_INET_XFRM_MODE_TUNNEL) += xfrm4_mode_tunnel.o
27obj-$(CONFIG_IP_PNP) += ipconfig.o 29obj-$(CONFIG_IP_PNP) += ipconfig.o
28obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o 30obj-$(CONFIG_IP_ROUTE_MULTIPATH_RR) += multipath_rr.o
29obj-$(CONFIG_IP_ROUTE_MULTIPATH_RANDOM) += multipath_random.o 31obj-$(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
25EXPORT_SYMBOL(xfrm4_rcv); 24EXPORT_SYMBOL(xfrm4_rcv);
26 25
27static 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
36static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq) 26static 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 */
24static 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
41static int xfrm4_transport_input(struct xfrm_state *x, struct sk_buff *skb)
42{
43 return 0;
44}
45
46static 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
53static int __init xfrm4_transport_init(void)
54{
55 return xfrm_register_mode(&xfrm4_transport_mode, AF_INET);
56}
57
58static 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
66module_init(xfrm4_transport_init);
67module_exit(xfrm4_transport_exit);
68MODULE_LICENSE("GPL");
69MODULE_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
17static 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 */
36static 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
74static 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
98out:
99 return err;
100}
101
102static 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
109static int __init xfrm4_tunnel_init(void)
110{
111 return xfrm_register_mode(&xfrm4_tunnel_mode, AF_INET);
112}
113
114static 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
122module_init(xfrm4_tunnel_init);
123module_exit(xfrm4_tunnel_exit);
124MODULE_LICENSE("GPL");
125MODULE_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 */
33static 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
76static int xfrm4_tunnel_check_size(struct sk_buff *skb) 19static 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)