162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* xfrm4_tunnel.c: Generic IP tunnel transformer. 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (C) 2003 David S. Miller (davem@redhat.com) 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#define pr_fmt(fmt) "IPsec: " fmt 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/skbuff.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <net/xfrm.h> 1262306a36Sopenharmony_ci#include <net/protocol.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic int ipip_output(struct xfrm_state *x, struct sk_buff *skb) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci skb_push(skb, -skb_network_offset(skb)); 1762306a36Sopenharmony_ci return 0; 1862306a36Sopenharmony_ci} 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int ipip_xfrm_rcv(struct xfrm_state *x, struct sk_buff *skb) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci return ip_hdr(skb)->protocol; 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic int ipip_init_state(struct xfrm_state *x, struct netlink_ext_ack *extack) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci if (x->props.mode != XFRM_MODE_TUNNEL) { 2862306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "IPv4 tunnel can only be used with tunnel mode"); 2962306a36Sopenharmony_ci return -EINVAL; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (x->encap) { 3362306a36Sopenharmony_ci NL_SET_ERR_MSG(extack, "IPv4 tunnel is not compatible with encapsulation"); 3462306a36Sopenharmony_ci return -EINVAL; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci x->props.header_len = sizeof(struct iphdr); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci return 0; 4062306a36Sopenharmony_ci} 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic void ipip_destroy(struct xfrm_state *x) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic const struct xfrm_type ipip_type = { 4762306a36Sopenharmony_ci .owner = THIS_MODULE, 4862306a36Sopenharmony_ci .proto = IPPROTO_IPIP, 4962306a36Sopenharmony_ci .init_state = ipip_init_state, 5062306a36Sopenharmony_ci .destructor = ipip_destroy, 5162306a36Sopenharmony_ci .input = ipip_xfrm_rcv, 5262306a36Sopenharmony_ci .output = ipip_output 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cistatic int xfrm_tunnel_rcv(struct sk_buff *skb) 5662306a36Sopenharmony_ci{ 5762306a36Sopenharmony_ci return xfrm4_rcv_spi(skb, IPPROTO_IPIP, ip_hdr(skb)->saddr); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic int xfrm_tunnel_err(struct sk_buff *skb, u32 info) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci return -ENOENT; 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cistatic struct xfrm_tunnel xfrm_tunnel_handler __read_mostly = { 6662306a36Sopenharmony_ci .handler = xfrm_tunnel_rcv, 6762306a36Sopenharmony_ci .err_handler = xfrm_tunnel_err, 6862306a36Sopenharmony_ci .priority = 4, 6962306a36Sopenharmony_ci}; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 7262306a36Sopenharmony_cistatic struct xfrm_tunnel xfrm64_tunnel_handler __read_mostly = { 7362306a36Sopenharmony_ci .handler = xfrm_tunnel_rcv, 7462306a36Sopenharmony_ci .err_handler = xfrm_tunnel_err, 7562306a36Sopenharmony_ci .priority = 3, 7662306a36Sopenharmony_ci}; 7762306a36Sopenharmony_ci#endif 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_cistatic int __init ipip_init(void) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci if (xfrm_register_type(&ipip_type, AF_INET) < 0) { 8262306a36Sopenharmony_ci pr_info("%s: can't add xfrm type\n", __func__); 8362306a36Sopenharmony_ci return -EAGAIN; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (xfrm4_tunnel_register(&xfrm_tunnel_handler, AF_INET)) { 8762306a36Sopenharmony_ci pr_info("%s: can't add xfrm handler for AF_INET\n", __func__); 8862306a36Sopenharmony_ci xfrm_unregister_type(&ipip_type, AF_INET); 8962306a36Sopenharmony_ci return -EAGAIN; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 9262306a36Sopenharmony_ci if (xfrm4_tunnel_register(&xfrm64_tunnel_handler, AF_INET6)) { 9362306a36Sopenharmony_ci pr_info("%s: can't add xfrm handler for AF_INET6\n", __func__); 9462306a36Sopenharmony_ci xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET); 9562306a36Sopenharmony_ci xfrm_unregister_type(&ipip_type, AF_INET); 9662306a36Sopenharmony_ci return -EAGAIN; 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci#endif 9962306a36Sopenharmony_ci return 0; 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic void __exit ipip_fini(void) 10362306a36Sopenharmony_ci{ 10462306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_IPV6) 10562306a36Sopenharmony_ci if (xfrm4_tunnel_deregister(&xfrm64_tunnel_handler, AF_INET6)) 10662306a36Sopenharmony_ci pr_info("%s: can't remove xfrm handler for AF_INET6\n", 10762306a36Sopenharmony_ci __func__); 10862306a36Sopenharmony_ci#endif 10962306a36Sopenharmony_ci if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET)) 11062306a36Sopenharmony_ci pr_info("%s: can't remove xfrm handler for AF_INET\n", 11162306a36Sopenharmony_ci __func__); 11262306a36Sopenharmony_ci xfrm_unregister_type(&ipip_type, AF_INET); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cimodule_init(ipip_init); 11662306a36Sopenharmony_cimodule_exit(ipip_fini); 11762306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 11862306a36Sopenharmony_ciMODULE_ALIAS_XFRM_TYPE(AF_INET, XFRM_PROTO_IPIP); 119