1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* xfrm6_protocol.c - Generic xfrm protocol multiplexer for ipv6. 3 * 4 * Copyright (C) 2013 secunet Security Networks AG 5 * 6 * Author: 7 * Steffen Klassert <steffen.klassert@secunet.com> 8 * 9 * Based on: 10 * net/ipv4/xfrm4_protocol.c 11 */ 12 13 #include <linux/init.h> 14 #include <linux/mutex.h> 15 #include <linux/skbuff.h> 16 #include <linux/icmpv6.h> 17 #include <net/ipv6.h> 18 #include <net/protocol.h> 19 #include <net/xfrm.h> 20 21 static struct xfrm6_protocol __rcu *esp6_handlers __read_mostly; 22 static struct xfrm6_protocol __rcu *ah6_handlers __read_mostly; 23 static struct xfrm6_protocol __rcu *ipcomp6_handlers __read_mostly; 24 static DEFINE_MUTEX(xfrm6_protocol_mutex); 25 26 static inline struct xfrm6_protocol __rcu **proto_handlers(u8 protocol) 27 { 28 switch (protocol) { 29 case IPPROTO_ESP: 30 return &esp6_handlers; 31 case IPPROTO_AH: 32 return &ah6_handlers; 33 case IPPROTO_COMP: 34 return &ipcomp6_handlers; 35 } 36 37 return NULL; 38 } 39 40 #define for_each_protocol_rcu(head, handler) \ 41 for (handler = rcu_dereference(head); \ 42 handler != NULL; \ 43 handler = rcu_dereference(handler->next)) \ 44 45 static int xfrm6_rcv_cb(struct sk_buff *skb, u8 protocol, int err) 46 { 47 int ret; 48 struct xfrm6_protocol *handler; 49 struct xfrm6_protocol __rcu **head = proto_handlers(protocol); 50 51 if (!head) 52 return 0; 53 54 for_each_protocol_rcu(*proto_handlers(protocol), handler) 55 if ((ret = handler->cb_handler(skb, err)) <= 0) 56 return ret; 57 58 return 0; 59 } 60 61 static int xfrm6_esp_rcv(struct sk_buff *skb) 62 { 63 int ret; 64 struct xfrm6_protocol *handler; 65 66 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 67 68 for_each_protocol_rcu(esp6_handlers, handler) 69 if ((ret = handler->handler(skb)) != -EINVAL) 70 return ret; 71 72 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 73 74 kfree_skb(skb); 75 return 0; 76 } 77 78 static int xfrm6_esp_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 79 u8 type, u8 code, int offset, __be32 info) 80 { 81 struct xfrm6_protocol *handler; 82 83 for_each_protocol_rcu(esp6_handlers, handler) 84 if (!handler->err_handler(skb, opt, type, code, offset, info)) 85 return 0; 86 87 return -ENOENT; 88 } 89 90 static int xfrm6_ah_rcv(struct sk_buff *skb) 91 { 92 int ret; 93 struct xfrm6_protocol *handler; 94 95 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 96 97 for_each_protocol_rcu(ah6_handlers, handler) 98 if ((ret = handler->handler(skb)) != -EINVAL) 99 return ret; 100 101 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 102 103 kfree_skb(skb); 104 return 0; 105 } 106 107 static int xfrm6_ah_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 108 u8 type, u8 code, int offset, __be32 info) 109 { 110 struct xfrm6_protocol *handler; 111 112 for_each_protocol_rcu(ah6_handlers, handler) 113 if (!handler->err_handler(skb, opt, type, code, offset, info)) 114 return 0; 115 116 return -ENOENT; 117 } 118 119 static int xfrm6_ipcomp_rcv(struct sk_buff *skb) 120 { 121 int ret; 122 struct xfrm6_protocol *handler; 123 124 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 125 126 for_each_protocol_rcu(ipcomp6_handlers, handler) 127 if ((ret = handler->handler(skb)) != -EINVAL) 128 return ret; 129 130 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 131 132 kfree_skb(skb); 133 return 0; 134 } 135 136 static int xfrm6_ipcomp_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 137 u8 type, u8 code, int offset, __be32 info) 138 { 139 struct xfrm6_protocol *handler; 140 141 for_each_protocol_rcu(ipcomp6_handlers, handler) 142 if (!handler->err_handler(skb, opt, type, code, offset, info)) 143 return 0; 144 145 return -ENOENT; 146 } 147 148 static const struct inet6_protocol esp6_protocol = { 149 .handler = xfrm6_esp_rcv, 150 .err_handler = xfrm6_esp_err, 151 .flags = INET6_PROTO_NOPOLICY, 152 }; 153 154 static const struct inet6_protocol ah6_protocol = { 155 .handler = xfrm6_ah_rcv, 156 .err_handler = xfrm6_ah_err, 157 .flags = INET6_PROTO_NOPOLICY, 158 }; 159 160 static const struct inet6_protocol ipcomp6_protocol = { 161 .handler = xfrm6_ipcomp_rcv, 162 .err_handler = xfrm6_ipcomp_err, 163 .flags = INET6_PROTO_NOPOLICY, 164 }; 165 166 static const struct xfrm_input_afinfo xfrm6_input_afinfo = { 167 .family = AF_INET6, 168 .callback = xfrm6_rcv_cb, 169 }; 170 171 static inline const struct inet6_protocol *netproto(unsigned char protocol) 172 { 173 switch (protocol) { 174 case IPPROTO_ESP: 175 return &esp6_protocol; 176 case IPPROTO_AH: 177 return &ah6_protocol; 178 case IPPROTO_COMP: 179 return &ipcomp6_protocol; 180 } 181 182 return NULL; 183 } 184 185 int xfrm6_protocol_register(struct xfrm6_protocol *handler, 186 unsigned char protocol) 187 { 188 struct xfrm6_protocol __rcu **pprev; 189 struct xfrm6_protocol *t; 190 bool add_netproto = false; 191 int ret = -EEXIST; 192 int priority = handler->priority; 193 194 if (!proto_handlers(protocol) || !netproto(protocol)) 195 return -EINVAL; 196 197 mutex_lock(&xfrm6_protocol_mutex); 198 199 if (!rcu_dereference_protected(*proto_handlers(protocol), 200 lockdep_is_held(&xfrm6_protocol_mutex))) 201 add_netproto = true; 202 203 for (pprev = proto_handlers(protocol); 204 (t = rcu_dereference_protected(*pprev, 205 lockdep_is_held(&xfrm6_protocol_mutex))) != NULL; 206 pprev = &t->next) { 207 if (t->priority < priority) 208 break; 209 if (t->priority == priority) 210 goto err; 211 } 212 213 handler->next = *pprev; 214 rcu_assign_pointer(*pprev, handler); 215 216 ret = 0; 217 218 err: 219 mutex_unlock(&xfrm6_protocol_mutex); 220 221 if (add_netproto) { 222 if (inet6_add_protocol(netproto(protocol), protocol)) { 223 pr_err("%s: can't add protocol\n", __func__); 224 ret = -EAGAIN; 225 } 226 } 227 228 return ret; 229 } 230 EXPORT_SYMBOL(xfrm6_protocol_register); 231 232 int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, 233 unsigned char protocol) 234 { 235 struct xfrm6_protocol __rcu **pprev; 236 struct xfrm6_protocol *t; 237 int ret = -ENOENT; 238 239 if (!proto_handlers(protocol) || !netproto(protocol)) 240 return -EINVAL; 241 242 mutex_lock(&xfrm6_protocol_mutex); 243 244 for (pprev = proto_handlers(protocol); 245 (t = rcu_dereference_protected(*pprev, 246 lockdep_is_held(&xfrm6_protocol_mutex))) != NULL; 247 pprev = &t->next) { 248 if (t == handler) { 249 *pprev = handler->next; 250 ret = 0; 251 break; 252 } 253 } 254 255 if (!rcu_dereference_protected(*proto_handlers(protocol), 256 lockdep_is_held(&xfrm6_protocol_mutex))) { 257 if (inet6_del_protocol(netproto(protocol), protocol) < 0) { 258 pr_err("%s: can't remove protocol\n", __func__); 259 ret = -EAGAIN; 260 } 261 } 262 263 mutex_unlock(&xfrm6_protocol_mutex); 264 265 synchronize_net(); 266 267 return ret; 268 } 269 EXPORT_SYMBOL(xfrm6_protocol_deregister); 270 271 int __init xfrm6_protocol_init(void) 272 { 273 return xfrm_input_register_afinfo(&xfrm6_input_afinfo); 274 } 275 276 void xfrm6_protocol_fini(void) 277 { 278 xfrm_input_unregister_afinfo(&xfrm6_input_afinfo); 279 } 280