mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
32b8a8e59c
This patch adds the support of IPv4 over Ipv4 for the module sit. The gain of this feature is to be able to have 4in4 and 6in4 over the same interface instead of having one interface for 6in4 and another for 4in4 even if encapsulation addresses are the same. To avoid conflicting with ipip module, sit IPv4 over IPv4 protocol is registered with a smaller priority. Signed-off-by: Nicolas Dichtel <nicolas.dichtel@6wind.com> Signed-off-by: David S. Miller <davem@davemloft.net>
118 lines
2.7 KiB
C
118 lines
2.7 KiB
C
/* xfrm4_tunnel.c: Generic IP tunnel transformer.
|
|
*
|
|
* Copyright (C) 2003 David S. Miller (davem@redhat.com)
|
|
*/
|
|
|
|
#define pr_fmt(fmt) "IPsec: " fmt
|
|
|
|
#include <linux/skbuff.h>
|
|
#include <linux/module.h>
|
|
#include <linux/mutex.h>
|
|
#include <net/xfrm.h>
|
|
#include <net/ip.h>
|
|
#include <net/protocol.h>
|
|
|
|
static int ipip_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
skb_push(skb, -skb_network_offset(skb));
|
|
return 0;
|
|
}
|
|
|
|
static int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
return ip_hdr(skb)->protocol;
|
|
}
|
|
|
|
static int ipip_init_state(struct xfrm_state *x)
|
|
{
|
|
if (x->props.mode != XFRM_MODE_TUNNEL)
|
|
return -EINVAL;
|
|
|
|
if (x->encap)
|
|
return -EINVAL;
|
|
|
|
x->props.header_len = sizeof(struct iphdr);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void ipip_destroy(struct xfrm_state *x)
|
|
{
|
|
}
|
|
|
|
static const struct xfrm_type ipip_type = {
|
|
.description = "IPIP",
|
|
.owner = THIS_MODULE,
|
|
.proto = IPPROTO_IPIP,
|
|
.init_state = ipip_init_state,
|
|
.destructor = ipip_destroy,
|
|
.input = ipip_xfrm_rcv,
|
|
.output = ipip_output
|
|
};
|
|
|
|
static int xfrm_tunnel_rcv(struct sk_buff *skb)
|
|
{
|
|
return xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr);
|
|
}
|
|
|
|
static int xfrm_tunnel_err(struct sk_buff *skb, u32 info)
|
|
{
|
|
return -ENOENT;
|
|
}
|
|
|
|
static struct xfrm_tunnel xfrm_tunnel_handler __read_mostly = {
|
|
.handler = xfrm_tunnel_rcv,
|
|
.err_handler = xfrm_tunnel_err,
|
|
.priority = 3,
|
|
};
|
|
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
static struct xfrm_tunnel xfrm64_tunnel_handler __read_mostly = {
|
|
.handler = xfrm_tunnel_rcv,
|
|
.err_handler = xfrm_tunnel_err,
|
|
.priority = 2,
|
|
};
|
|
#endif
|
|
|
|
static int __init ipip_init(void)
|
|
{
|
|
if (xfrm_register_type(&ipip_type, AF_INET) < 0) {
|
|
pr_info("%s: can't add xfrm type\n", __func__);
|
|
return -EAGAIN;
|
|
}
|
|
|
|
if (xfrm4_tunnel_register(&xfrm_tunnel_handler, AF_INET)) {
|
|
pr_info("%s: can't add xfrm handler for AF_INET\n", __func__);
|
|
xfrm_unregister_type(&ipip_type, AF_INET);
|
|
return -EAGAIN;
|
|
}
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
if (xfrm4_tunnel_register(&xfrm64_tunnel_handler, AF_INET6)) {
|
|
pr_info("%s: can't add xfrm handler for AF_INET6\n", __func__);
|
|
xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET);
|
|
xfrm_unregister_type(&ipip_type, AF_INET);
|
|
return -EAGAIN;
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
static void __exit ipip_fini(void)
|
|
{
|
|
#if IS_ENABLED(CONFIG_IPV6)
|
|
if (xfrm4_tunnel_deregister(&xfrm64_tunnel_handler, AF_INET6))
|
|
pr_info("%s: can't remove xfrm handler for AF_INET6\n",
|
|
__func__);
|
|
#endif
|
|
if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET))
|
|
pr_info("%s: can't remove xfrm handler for AF_INET\n",
|
|
__func__);
|
|
if (xfrm_unregister_type(&ipip_type, AF_INET) < 0)
|
|
pr_info("%s: can't remove xfrm type\n", __func__);
|
|
}
|
|
|
|
module_init(ipip_init);
|
|
module_exit(ipip_fini);
|
|
MODULE_LICENSE("GPL");
|
|
MODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_IPIP);
|