xref: /linux/net/ipv4/xfrm4_protocol.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
23328715eSSteffen Klassert /* xfrm4_protocol.c - Generic xfrm protocol multiplexer.
33328715eSSteffen Klassert  *
43328715eSSteffen Klassert  * Copyright (C) 2013 secunet Security Networks AG
53328715eSSteffen Klassert  *
63328715eSSteffen Klassert  * Author:
73328715eSSteffen Klassert  * Steffen Klassert <steffen.klassert@secunet.com>
83328715eSSteffen Klassert  *
93328715eSSteffen Klassert  * Based on:
103328715eSSteffen Klassert  * net/ipv4/tunnel4.c
113328715eSSteffen Klassert  */
123328715eSSteffen Klassert 
133328715eSSteffen Klassert #include <linux/init.h>
143328715eSSteffen Klassert #include <linux/mutex.h>
153328715eSSteffen Klassert #include <linux/skbuff.h>
163328715eSSteffen Klassert #include <net/icmp.h>
173328715eSSteffen Klassert #include <net/ip.h>
183328715eSSteffen Klassert #include <net/protocol.h>
193328715eSSteffen Klassert #include <net/xfrm.h>
203328715eSSteffen Klassert 
213328715eSSteffen Klassert static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly;
223328715eSSteffen Klassert static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly;
233328715eSSteffen Klassert static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly;
243328715eSSteffen Klassert static DEFINE_MUTEX(xfrm4_protocol_mutex);
253328715eSSteffen Klassert 
proto_handlers(u8 protocol)263328715eSSteffen Klassert static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol)
273328715eSSteffen Klassert {
283328715eSSteffen Klassert 	switch (protocol) {
293328715eSSteffen Klassert 	case IPPROTO_ESP:
303328715eSSteffen Klassert 		return &esp4_handlers;
313328715eSSteffen Klassert 	case IPPROTO_AH:
323328715eSSteffen Klassert 		return &ah4_handlers;
333328715eSSteffen Klassert 	case IPPROTO_COMP:
343328715eSSteffen Klassert 		return &ipcomp4_handlers;
353328715eSSteffen Klassert 	}
363328715eSSteffen Klassert 
373328715eSSteffen Klassert 	return NULL;
383328715eSSteffen Klassert }
393328715eSSteffen Klassert 
403328715eSSteffen Klassert #define for_each_protocol_rcu(head, handler)		\
413328715eSSteffen Klassert 	for (handler = rcu_dereference(head);		\
423328715eSSteffen Klassert 	     handler != NULL;				\
433328715eSSteffen Klassert 	     handler = rcu_dereference(handler->next))	\
443328715eSSteffen Klassert 
xfrm4_rcv_cb(struct sk_buff * skb,u8 protocol,int err)45bb9cd077SFlorian Westphal static int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
463328715eSSteffen Klassert {
473328715eSSteffen Klassert 	int ret;
483328715eSSteffen Klassert 	struct xfrm4_protocol *handler;
4961622cc6SSteffen Klassert 	struct xfrm4_protocol __rcu **head = proto_handlers(protocol);
503328715eSSteffen Klassert 
5161622cc6SSteffen Klassert 	if (!head)
5261622cc6SSteffen Klassert 		return 0;
5361622cc6SSteffen Klassert 
5461622cc6SSteffen Klassert 	for_each_protocol_rcu(*head, handler)
553328715eSSteffen Klassert 		if ((ret = handler->cb_handler(skb, err)) <= 0)
563328715eSSteffen Klassert 			return ret;
573328715eSSteffen Klassert 
583328715eSSteffen Klassert 	return 0;
593328715eSSteffen Klassert }
603328715eSSteffen Klassert 
xfrm4_rcv_encap(struct sk_buff * skb,int nexthdr,__be32 spi,int encap_type)613328715eSSteffen Klassert int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
623328715eSSteffen Klassert 		    int encap_type)
633328715eSSteffen Klassert {
643328715eSSteffen Klassert 	int ret;
653328715eSSteffen Klassert 	struct xfrm4_protocol *handler;
6661622cc6SSteffen Klassert 	struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr);
673328715eSSteffen Klassert 
6870be6c91SSteffen Klassert 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
693328715eSSteffen Klassert 	XFRM_SPI_SKB_CB(skb)->family = AF_INET;
703328715eSSteffen Klassert 	XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
713328715eSSteffen Klassert 
7261622cc6SSteffen Klassert 	if (!head)
7361622cc6SSteffen Klassert 		goto out;
7461622cc6SSteffen Klassert 
75*cac3c716SSabrina Dubroca 	if (!skb_dst(skb)) {
76*cac3c716SSabrina Dubroca 		const struct iphdr *iph = ip_hdr(skb);
77*cac3c716SSabrina Dubroca 
78*cac3c716SSabrina Dubroca 		if (ip_route_input_noref(skb, iph->daddr, iph->saddr,
79*cac3c716SSabrina Dubroca 					 iph->tos, skb->dev))
80*cac3c716SSabrina Dubroca 			goto drop;
81*cac3c716SSabrina Dubroca 	}
82*cac3c716SSabrina Dubroca 
8361622cc6SSteffen Klassert 	for_each_protocol_rcu(*head, handler)
843328715eSSteffen Klassert 		if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL)
853328715eSSteffen Klassert 			return ret;
863328715eSSteffen Klassert 
8761622cc6SSteffen Klassert out:
883328715eSSteffen Klassert 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
893328715eSSteffen Klassert 
90*cac3c716SSabrina Dubroca drop:
913328715eSSteffen Klassert 	kfree_skb(skb);
923328715eSSteffen Klassert 	return 0;
933328715eSSteffen Klassert }
943328715eSSteffen Klassert EXPORT_SYMBOL(xfrm4_rcv_encap);
953328715eSSteffen Klassert 
xfrm4_esp_rcv(struct sk_buff * skb)963328715eSSteffen Klassert static int xfrm4_esp_rcv(struct sk_buff *skb)
973328715eSSteffen Klassert {
983328715eSSteffen Klassert 	int ret;
993328715eSSteffen Klassert 	struct xfrm4_protocol *handler;
1003328715eSSteffen Klassert 
10170be6c91SSteffen Klassert 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
10270be6c91SSteffen Klassert 
1033328715eSSteffen Klassert 	for_each_protocol_rcu(esp4_handlers, handler)
1043328715eSSteffen Klassert 		if ((ret = handler->handler(skb)) != -EINVAL)
1053328715eSSteffen Klassert 			return ret;
1063328715eSSteffen Klassert 
1073328715eSSteffen Klassert 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
1083328715eSSteffen Klassert 
1093328715eSSteffen Klassert 	kfree_skb(skb);
1103328715eSSteffen Klassert 	return 0;
1113328715eSSteffen Klassert }
1123328715eSSteffen Klassert 
xfrm4_esp_err(struct sk_buff * skb,u32 info)11332bbd879SStefano Brivio static int xfrm4_esp_err(struct sk_buff *skb, u32 info)
1143328715eSSteffen Klassert {
1153328715eSSteffen Klassert 	struct xfrm4_protocol *handler;
1163328715eSSteffen Klassert 
1173328715eSSteffen Klassert 	for_each_protocol_rcu(esp4_handlers, handler)
1183328715eSSteffen Klassert 		if (!handler->err_handler(skb, info))
11932bbd879SStefano Brivio 			return 0;
12032bbd879SStefano Brivio 
12132bbd879SStefano Brivio 	return -ENOENT;
1223328715eSSteffen Klassert }
1233328715eSSteffen Klassert 
xfrm4_ah_rcv(struct sk_buff * skb)1243328715eSSteffen Klassert static int xfrm4_ah_rcv(struct sk_buff *skb)
1253328715eSSteffen Klassert {
1263328715eSSteffen Klassert 	int ret;
1273328715eSSteffen Klassert 	struct xfrm4_protocol *handler;
1283328715eSSteffen Klassert 
12970be6c91SSteffen Klassert 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
13070be6c91SSteffen Klassert 
1313328715eSSteffen Klassert 	for_each_protocol_rcu(ah4_handlers, handler)
1323328715eSSteffen Klassert 		if ((ret = handler->handler(skb)) != -EINVAL)
1331759389eSChristoph Paasch 			return ret;
1343328715eSSteffen Klassert 
1353328715eSSteffen Klassert 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
1363328715eSSteffen Klassert 
1373328715eSSteffen Klassert 	kfree_skb(skb);
1383328715eSSteffen Klassert 	return 0;
1393328715eSSteffen Klassert }
1403328715eSSteffen Klassert 
xfrm4_ah_err(struct sk_buff * skb,u32 info)14132bbd879SStefano Brivio static int xfrm4_ah_err(struct sk_buff *skb, u32 info)
1423328715eSSteffen Klassert {
1433328715eSSteffen Klassert 	struct xfrm4_protocol *handler;
1443328715eSSteffen Klassert 
1453328715eSSteffen Klassert 	for_each_protocol_rcu(ah4_handlers, handler)
1463328715eSSteffen Klassert 		if (!handler->err_handler(skb, info))
14732bbd879SStefano Brivio 			return 0;
14832bbd879SStefano Brivio 
14932bbd879SStefano Brivio 	return -ENOENT;
1503328715eSSteffen Klassert }
1513328715eSSteffen Klassert 
xfrm4_ipcomp_rcv(struct sk_buff * skb)1523328715eSSteffen Klassert static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
1533328715eSSteffen Klassert {
1543328715eSSteffen Klassert 	int ret;
1553328715eSSteffen Klassert 	struct xfrm4_protocol *handler;
1563328715eSSteffen Klassert 
15770be6c91SSteffen Klassert 	XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
15870be6c91SSteffen Klassert 
1593328715eSSteffen Klassert 	for_each_protocol_rcu(ipcomp4_handlers, handler)
1603328715eSSteffen Klassert 		if ((ret = handler->handler(skb)) != -EINVAL)
1613328715eSSteffen Klassert 			return ret;
1623328715eSSteffen Klassert 
1633328715eSSteffen Klassert 	icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
1643328715eSSteffen Klassert 
1653328715eSSteffen Klassert 	kfree_skb(skb);
1663328715eSSteffen Klassert 	return 0;
1673328715eSSteffen Klassert }
1683328715eSSteffen Klassert 
xfrm4_ipcomp_err(struct sk_buff * skb,u32 info)16932bbd879SStefano Brivio static int xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
1703328715eSSteffen Klassert {
1713328715eSSteffen Klassert 	struct xfrm4_protocol *handler;
1723328715eSSteffen Klassert 
1733328715eSSteffen Klassert 	for_each_protocol_rcu(ipcomp4_handlers, handler)
1743328715eSSteffen Klassert 		if (!handler->err_handler(skb, info))
17532bbd879SStefano Brivio 			return 0;
17632bbd879SStefano Brivio 
17732bbd879SStefano Brivio 	return -ENOENT;
1783328715eSSteffen Klassert }
1793328715eSSteffen Klassert 
1803328715eSSteffen Klassert static const struct net_protocol esp4_protocol = {
1813328715eSSteffen Klassert 	.handler	=	xfrm4_esp_rcv,
1823328715eSSteffen Klassert 	.err_handler	=	xfrm4_esp_err,
1833328715eSSteffen Klassert 	.no_policy	=	1,
1843328715eSSteffen Klassert };
1853328715eSSteffen Klassert 
1863328715eSSteffen Klassert static const struct net_protocol ah4_protocol = {
1873328715eSSteffen Klassert 	.handler	=	xfrm4_ah_rcv,
1883328715eSSteffen Klassert 	.err_handler	=	xfrm4_ah_err,
1893328715eSSteffen Klassert 	.no_policy	=	1,
1903328715eSSteffen Klassert };
1913328715eSSteffen Klassert 
1923328715eSSteffen Klassert static const struct net_protocol ipcomp4_protocol = {
1933328715eSSteffen Klassert 	.handler	=	xfrm4_ipcomp_rcv,
1943328715eSSteffen Klassert 	.err_handler	=	xfrm4_ipcomp_err,
1953328715eSSteffen Klassert 	.no_policy	=	1,
1963328715eSSteffen Klassert };
1973328715eSSteffen Klassert 
198960fdfdeSFlorian Westphal static const struct xfrm_input_afinfo xfrm4_input_afinfo = {
1992f32b51bSSteffen Klassert 	.family		=	AF_INET,
2002f32b51bSSteffen Klassert 	.callback	=	xfrm4_rcv_cb,
2012f32b51bSSteffen Klassert };
2022f32b51bSSteffen Klassert 
netproto(unsigned char protocol)2033328715eSSteffen Klassert static inline const struct net_protocol *netproto(unsigned char protocol)
2043328715eSSteffen Klassert {
2053328715eSSteffen Klassert 	switch (protocol) {
2063328715eSSteffen Klassert 	case IPPROTO_ESP:
2073328715eSSteffen Klassert 		return &esp4_protocol;
2083328715eSSteffen Klassert 	case IPPROTO_AH:
2093328715eSSteffen Klassert 		return &ah4_protocol;
2103328715eSSteffen Klassert 	case IPPROTO_COMP:
2113328715eSSteffen Klassert 		return &ipcomp4_protocol;
2123328715eSSteffen Klassert 	}
2133328715eSSteffen Klassert 
2143328715eSSteffen Klassert 	return NULL;
2153328715eSSteffen Klassert }
2163328715eSSteffen Klassert 
xfrm4_protocol_register(struct xfrm4_protocol * handler,unsigned char protocol)2173328715eSSteffen Klassert int xfrm4_protocol_register(struct xfrm4_protocol *handler,
2183328715eSSteffen Klassert 			    unsigned char protocol)
2193328715eSSteffen Klassert {
2203328715eSSteffen Klassert 	struct xfrm4_protocol __rcu **pprev;
2213328715eSSteffen Klassert 	struct xfrm4_protocol *t;
2223328715eSSteffen Klassert 	bool add_netproto = false;
2233328715eSSteffen Klassert 	int ret = -EEXIST;
2243328715eSSteffen Klassert 	int priority = handler->priority;
2253328715eSSteffen Klassert 
22661622cc6SSteffen Klassert 	if (!proto_handlers(protocol) || !netproto(protocol))
22761622cc6SSteffen Klassert 		return -EINVAL;
22861622cc6SSteffen Klassert 
2293328715eSSteffen Klassert 	mutex_lock(&xfrm4_protocol_mutex);
2303328715eSSteffen Klassert 
2313328715eSSteffen Klassert 	if (!rcu_dereference_protected(*proto_handlers(protocol),
2323328715eSSteffen Klassert 				       lockdep_is_held(&xfrm4_protocol_mutex)))
2333328715eSSteffen Klassert 		add_netproto = true;
2343328715eSSteffen Klassert 
2353328715eSSteffen Klassert 	for (pprev = proto_handlers(protocol);
2363328715eSSteffen Klassert 	     (t = rcu_dereference_protected(*pprev,
2373328715eSSteffen Klassert 			lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
2383328715eSSteffen Klassert 	     pprev = &t->next) {
2393328715eSSteffen Klassert 		if (t->priority < priority)
2403328715eSSteffen Klassert 			break;
2413328715eSSteffen Klassert 		if (t->priority == priority)
2423328715eSSteffen Klassert 			goto err;
2433328715eSSteffen Klassert 	}
2443328715eSSteffen Klassert 
2453328715eSSteffen Klassert 	handler->next = *pprev;
2463328715eSSteffen Klassert 	rcu_assign_pointer(*pprev, handler);
2473328715eSSteffen Klassert 
2483328715eSSteffen Klassert 	ret = 0;
2493328715eSSteffen Klassert 
2503328715eSSteffen Klassert err:
2513328715eSSteffen Klassert 	mutex_unlock(&xfrm4_protocol_mutex);
2523328715eSSteffen Klassert 
2533328715eSSteffen Klassert 	if (add_netproto) {
2543328715eSSteffen Klassert 		if (inet_add_protocol(netproto(protocol), protocol)) {
2553328715eSSteffen Klassert 			pr_err("%s: can't add protocol\n", __func__);
2563328715eSSteffen Klassert 			ret = -EAGAIN;
2573328715eSSteffen Klassert 		}
2583328715eSSteffen Klassert 	}
2593328715eSSteffen Klassert 
2603328715eSSteffen Klassert 	return ret;
2613328715eSSteffen Klassert }
2623328715eSSteffen Klassert EXPORT_SYMBOL(xfrm4_protocol_register);
2633328715eSSteffen Klassert 
xfrm4_protocol_deregister(struct xfrm4_protocol * handler,unsigned char protocol)2643328715eSSteffen Klassert int xfrm4_protocol_deregister(struct xfrm4_protocol *handler,
2653328715eSSteffen Klassert 			      unsigned char protocol)
2663328715eSSteffen Klassert {
2673328715eSSteffen Klassert 	struct xfrm4_protocol __rcu **pprev;
2683328715eSSteffen Klassert 	struct xfrm4_protocol *t;
2693328715eSSteffen Klassert 	int ret = -ENOENT;
2703328715eSSteffen Klassert 
27161622cc6SSteffen Klassert 	if (!proto_handlers(protocol) || !netproto(protocol))
27261622cc6SSteffen Klassert 		return -EINVAL;
27361622cc6SSteffen Klassert 
2743328715eSSteffen Klassert 	mutex_lock(&xfrm4_protocol_mutex);
2753328715eSSteffen Klassert 
2763328715eSSteffen Klassert 	for (pprev = proto_handlers(protocol);
2773328715eSSteffen Klassert 	     (t = rcu_dereference_protected(*pprev,
2783328715eSSteffen Klassert 			lockdep_is_held(&xfrm4_protocol_mutex))) != NULL;
2793328715eSSteffen Klassert 	     pprev = &t->next) {
2803328715eSSteffen Klassert 		if (t == handler) {
2813328715eSSteffen Klassert 			*pprev = handler->next;
2823328715eSSteffen Klassert 			ret = 0;
2833328715eSSteffen Klassert 			break;
2843328715eSSteffen Klassert 		}
2853328715eSSteffen Klassert 	}
2863328715eSSteffen Klassert 
2873328715eSSteffen Klassert 	if (!rcu_dereference_protected(*proto_handlers(protocol),
2883328715eSSteffen Klassert 				       lockdep_is_held(&xfrm4_protocol_mutex))) {
2893328715eSSteffen Klassert 		if (inet_del_protocol(netproto(protocol), protocol) < 0) {
2903328715eSSteffen Klassert 			pr_err("%s: can't remove protocol\n", __func__);
2913328715eSSteffen Klassert 			ret = -EAGAIN;
2923328715eSSteffen Klassert 		}
2933328715eSSteffen Klassert 	}
2943328715eSSteffen Klassert 
2953328715eSSteffen Klassert 	mutex_unlock(&xfrm4_protocol_mutex);
2963328715eSSteffen Klassert 
2973328715eSSteffen Klassert 	synchronize_net();
2983328715eSSteffen Klassert 
2993328715eSSteffen Klassert 	return ret;
3003328715eSSteffen Klassert }
3013328715eSSteffen Klassert EXPORT_SYMBOL(xfrm4_protocol_deregister);
3022f32b51bSSteffen Klassert 
xfrm4_protocol_init(void)3032f32b51bSSteffen Klassert void __init xfrm4_protocol_init(void)
3042f32b51bSSteffen Klassert {
3052f32b51bSSteffen Klassert 	xfrm_input_register_afinfo(&xfrm4_input_afinfo);
3062f32b51bSSteffen Klassert }
307