1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* xfrm6_protocol.c - Generic xfrm protocol multiplexer for ipv6.
4 * Copyright (C) 2013 secunet Security Networks AG
7 * Steffen Klassert <steffen.klassert@secunet.com>
10 * net/ipv4/xfrm4_protocol.c
13 #include <linux/init.h>
14 #include <linux/mutex.h>
15 #include <linux/skbuff.h>
16 #include <linux/icmpv6.h>
17 #include <net/ip6_route.h>
19 #include <net/protocol.h>
22 static struct xfrm6_protocol __rcu
*esp6_handlers __read_mostly
;
23 static struct xfrm6_protocol __rcu
*ah6_handlers __read_mostly
;
24 static struct xfrm6_protocol __rcu
*ipcomp6_handlers __read_mostly
;
25 static DEFINE_MUTEX(xfrm6_protocol_mutex
);
27 static inline struct xfrm6_protocol __rcu
**proto_handlers(u8 protocol
)
31 return &esp6_handlers
;
35 return &ipcomp6_handlers
;
41 #define for_each_protocol_rcu(head, handler) \
42 for (handler = rcu_dereference(head); \
44 handler = rcu_dereference(handler->next)) \
46 static int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
49 struct xfrm6_protocol
*handler
;
50 struct xfrm6_protocol __rcu
**head
= proto_handlers(protocol
);
55 for_each_protocol_rcu(*proto_handlers(protocol
), handler
)
56 if ((ret
= handler
->cb_handler(skb
, err
)) <= 0)
62 int xfrm6_rcv_encap(struct sk_buff
*skb
, int nexthdr
, __be32 spi
,
66 struct xfrm6_protocol
*handler
;
67 struct xfrm6_protocol __rcu
**head
= proto_handlers(nexthdr
);
69 XFRM_TUNNEL_SKB_CB(skb
)->tunnel
.ip6
= NULL
;
70 XFRM_SPI_SKB_CB(skb
)->family
= AF_INET6
;
71 XFRM_SPI_SKB_CB(skb
)->daddroff
= offsetof(struct ipv6hdr
, daddr
);
77 const struct ipv6hdr
*ip6h
= ipv6_hdr(skb
);
78 int flags
= RT6_LOOKUP_F_HAS_SADDR
;
79 struct dst_entry
*dst
;
81 .flowi6_iif
= skb
->dev
->ifindex
,
84 .flowlabel
= ip6_flowinfo(ip6h
),
85 .flowi6_mark
= skb
->mark
,
86 .flowi6_proto
= ip6h
->nexthdr
,
89 dst
= ip6_route_input_lookup(dev_net(skb
->dev
), skb
->dev
, &fl6
,
93 skb_dst_set(skb
, dst
);
96 for_each_protocol_rcu(*head
, handler
)
97 if ((ret
= handler
->input_handler(skb
, nexthdr
, spi
, encap_type
)) != -EINVAL
)
101 icmpv6_send(skb
, ICMPV6_DEST_UNREACH
, ICMPV6_PORT_UNREACH
, 0);
107 EXPORT_SYMBOL(xfrm6_rcv_encap
);
109 static int xfrm6_esp_rcv(struct sk_buff
*skb
)
112 struct xfrm6_protocol
*handler
;
114 XFRM_TUNNEL_SKB_CB(skb
)->tunnel
.ip6
= NULL
;
116 for_each_protocol_rcu(esp6_handlers
, handler
)
117 if ((ret
= handler
->handler(skb
)) != -EINVAL
)
120 icmpv6_send(skb
, ICMPV6_DEST_UNREACH
, ICMPV6_PORT_UNREACH
, 0);
126 static int xfrm6_esp_err(struct sk_buff
*skb
, struct inet6_skb_parm
*opt
,
127 u8 type
, u8 code
, int offset
, __be32 info
)
129 struct xfrm6_protocol
*handler
;
131 for_each_protocol_rcu(esp6_handlers
, handler
)
132 if (!handler
->err_handler(skb
, opt
, type
, code
, offset
, info
))
138 static int xfrm6_ah_rcv(struct sk_buff
*skb
)
141 struct xfrm6_protocol
*handler
;
143 XFRM_TUNNEL_SKB_CB(skb
)->tunnel
.ip6
= NULL
;
145 for_each_protocol_rcu(ah6_handlers
, handler
)
146 if ((ret
= handler
->handler(skb
)) != -EINVAL
)
149 icmpv6_send(skb
, ICMPV6_DEST_UNREACH
, ICMPV6_PORT_UNREACH
, 0);
155 static int xfrm6_ah_err(struct sk_buff
*skb
, struct inet6_skb_parm
*opt
,
156 u8 type
, u8 code
, int offset
, __be32 info
)
158 struct xfrm6_protocol
*handler
;
160 for_each_protocol_rcu(ah6_handlers
, handler
)
161 if (!handler
->err_handler(skb
, opt
, type
, code
, offset
, info
))
167 static int xfrm6_ipcomp_rcv(struct sk_buff
*skb
)
170 struct xfrm6_protocol
*handler
;
172 XFRM_TUNNEL_SKB_CB(skb
)->tunnel
.ip6
= NULL
;
174 for_each_protocol_rcu(ipcomp6_handlers
, handler
)
175 if ((ret
= handler
->handler(skb
)) != -EINVAL
)
178 icmpv6_send(skb
, ICMPV6_DEST_UNREACH
, ICMPV6_PORT_UNREACH
, 0);
184 static int xfrm6_ipcomp_err(struct sk_buff
*skb
, struct inet6_skb_parm
*opt
,
185 u8 type
, u8 code
, int offset
, __be32 info
)
187 struct xfrm6_protocol
*handler
;
189 for_each_protocol_rcu(ipcomp6_handlers
, handler
)
190 if (!handler
->err_handler(skb
, opt
, type
, code
, offset
, info
))
196 static const struct inet6_protocol esp6_protocol
= {
197 .handler
= xfrm6_esp_rcv
,
198 .err_handler
= xfrm6_esp_err
,
199 .flags
= INET6_PROTO_NOPOLICY
,
202 static const struct inet6_protocol ah6_protocol
= {
203 .handler
= xfrm6_ah_rcv
,
204 .err_handler
= xfrm6_ah_err
,
205 .flags
= INET6_PROTO_NOPOLICY
,
208 static const struct inet6_protocol ipcomp6_protocol
= {
209 .handler
= xfrm6_ipcomp_rcv
,
210 .err_handler
= xfrm6_ipcomp_err
,
211 .flags
= INET6_PROTO_NOPOLICY
,
214 static const struct xfrm_input_afinfo xfrm6_input_afinfo
= {
216 .callback
= xfrm6_rcv_cb
,
219 static inline const struct inet6_protocol
*netproto(unsigned char protocol
)
223 return &esp6_protocol
;
225 return &ah6_protocol
;
227 return &ipcomp6_protocol
;
233 int xfrm6_protocol_register(struct xfrm6_protocol
*handler
,
234 unsigned char protocol
)
236 struct xfrm6_protocol __rcu
**pprev
;
237 struct xfrm6_protocol
*t
;
238 bool add_netproto
= false;
240 int priority
= handler
->priority
;
242 if (!proto_handlers(protocol
) || !netproto(protocol
))
245 mutex_lock(&xfrm6_protocol_mutex
);
247 if (!rcu_dereference_protected(*proto_handlers(protocol
),
248 lockdep_is_held(&xfrm6_protocol_mutex
)))
251 for (pprev
= proto_handlers(protocol
);
252 (t
= rcu_dereference_protected(*pprev
,
253 lockdep_is_held(&xfrm6_protocol_mutex
))) != NULL
;
255 if (t
->priority
< priority
)
257 if (t
->priority
== priority
)
261 handler
->next
= *pprev
;
262 rcu_assign_pointer(*pprev
, handler
);
267 mutex_unlock(&xfrm6_protocol_mutex
);
270 if (inet6_add_protocol(netproto(protocol
), protocol
)) {
271 pr_err("%s: can't add protocol\n", __func__
);
278 EXPORT_SYMBOL(xfrm6_protocol_register
);
280 int xfrm6_protocol_deregister(struct xfrm6_protocol
*handler
,
281 unsigned char protocol
)
283 struct xfrm6_protocol __rcu
**pprev
;
284 struct xfrm6_protocol
*t
;
287 if (!proto_handlers(protocol
) || !netproto(protocol
))
290 mutex_lock(&xfrm6_protocol_mutex
);
292 for (pprev
= proto_handlers(protocol
);
293 (t
= rcu_dereference_protected(*pprev
,
294 lockdep_is_held(&xfrm6_protocol_mutex
))) != NULL
;
297 *pprev
= handler
->next
;
303 if (!rcu_dereference_protected(*proto_handlers(protocol
),
304 lockdep_is_held(&xfrm6_protocol_mutex
))) {
305 if (inet6_del_protocol(netproto(protocol
), protocol
) < 0) {
306 pr_err("%s: can't remove protocol\n", __func__
);
311 mutex_unlock(&xfrm6_protocol_mutex
);
317 EXPORT_SYMBOL(xfrm6_protocol_deregister
);
319 int __init
xfrm6_protocol_init(void)
321 return xfrm_input_register_afinfo(&xfrm6_input_afinfo
);
324 void xfrm6_protocol_fini(void)
326 xfrm_input_unregister_afinfo(&xfrm6_input_afinfo
);