[IPSEC]: Fix pure tunnel modes involving IPv6
[linux-2.6.git] / net / ipv4 / xfrm4_tunnel.c
1 /* xfrm4_tunnel.c: Generic IP tunnel transformer.
2  *
3  * Copyright (C) 2003 David S. Miller (davem@redhat.com)
4  */
5
6 #include <linux/skbuff.h>
7 #include <linux/module.h>
8 #include <linux/mutex.h>
9 #include <net/xfrm.h>
10 #include <net/ip.h>
11 #include <net/protocol.h>
12
13 static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
14 {
15         skb_push(skb, -skb_network_offset(skb));
16         return 0;
17 }
18
19 static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb)
20 {
21         return ip_hdr(skb)->protocol;
22 }
23
24 static int ipip_init_state(struct xfrm_state *x)
25 {
26         if (x->props.mode != XFRM_MODE_TUNNEL)
27                 return -EINVAL;
28
29         if (x->encap)
30                 return -EINVAL;
31
32         x->props.header_len = sizeof(struct iphdr);
33
34         return 0;
35 }
36
37 static void ipip_destroy(struct xfrm_state *x)
38 {
39 }
40
41 static struct xfrm_type ipip_type = {
42         .description    = "IPIP",
43         .owner          = THIS_MODULE,
44         .proto          = IPPROTO_IPIP,
45         .init_state     = ipip_init_state,
46         .destructor     = ipip_destroy,
47         .input          = ipip_xfrm_rcv,
48         .output         = ipip_output
49 };
50
51 static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
52 {
53         return -ENOENT;
54 }
55
56 static struct xfrm_tunnel xfrm_tunnel_handler = {
57         .handler        =       xfrm4_rcv,
58         .err_handler    =       xfrm_tunnel_err,
59         .priority       =       2,
60 };
61
62 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
63 static struct xfrm_tunnel xfrm64_tunnel_handler = {
64         .handler        =       xfrm4_rcv,
65         .err_handler    =       xfrm_tunnel_err,
66         .priority       =       2,
67 };
68 #endif
69
70 static int __init ipip_init(void)
71 {
72         if (xfrm_register_type(&ipip_type, AF_INET) < 0) {
73                 printk(KERN_INFO "ipip init: can't add xfrm type\n");
74                 return -EAGAIN;
75         }
76
77         if (xfrm4_tunnel_register(&xfrm_tunnel_handler, AF_INET)) {
78                 printk(KERN_INFO "ipip init: can't add xfrm handler for AF_INET\n");
79                 xfrm_unregister_type(&ipip_type, AF_INET);
80                 return -EAGAIN;
81         }
82 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
83         if (xfrm4_tunnel_register(&xfrm64_tunnel_handler, AF_INET6)) {
84                 printk(KERN_INFO "ipip init: can't add xfrm handler for AF_INET6\n");
85                 xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET);
86                 xfrm_unregister_type(&ipip_type, AF_INET);
87                 return -EAGAIN;
88         }
89 #endif
90         return 0;
91 }
92
93 static void __exit ipip_fini(void)
94 {
95 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
96         if (xfrm4_tunnel_deregister(&xfrm64_tunnel_handler, AF_INET6))
97                 printk(KERN_INFO "ipip close: can't remove xfrm handler for AF_INET6\n");
98 #endif
99         if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET))
100                 printk(KERN_INFO "ipip close: can't remove xfrm handler for AF_INET\n");
101         if (xfrm_unregister_type(&ipip_type, AF_INET) < 0)
102                 printk(KERN_INFO "ipip close: can't remove xfrm type\n");
103 }
104
105 module_init(ipip_init);
106 module_exit(ipip_fini);
107 MODULE_LICENSE("GPL");
108 MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_IPIP);