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