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 static 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 65 static int xfrm6_esp_rcv(struct sk_buff *skb) 66 { 67 int ret; 68 struct xfrm6_protocol *handler; 69 70 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 71 72 for_each_protocol_rcu(esp6_handlers, handler) 73 if ((ret = handler->handler(skb)) != -EINVAL) 74 return ret; 75 76 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 77 78 kfree_skb(skb); 79 return 0; 80 } 81 82 static int xfrm6_esp_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 83 u8 type, u8 code, int offset, __be32 info) 84 { 85 struct xfrm6_protocol *handler; 86 87 for_each_protocol_rcu(esp6_handlers, handler) 88 if (!handler->err_handler(skb, opt, type, code, offset, info)) 89 return 0; 90 91 return -ENOENT; 92 } 93 94 static int xfrm6_ah_rcv(struct sk_buff *skb) 95 { 96 int ret; 97 struct xfrm6_protocol *handler; 98 99 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 100 101 for_each_protocol_rcu(ah6_handlers, handler) 102 if ((ret = handler->handler(skb)) != -EINVAL) 103 return ret; 104 105 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 106 107 kfree_skb(skb); 108 return 0; 109 } 110 111 static int xfrm6_ah_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 112 u8 type, u8 code, int offset, __be32 info) 113 { 114 struct xfrm6_protocol *handler; 115 116 for_each_protocol_rcu(ah6_handlers, handler) 117 if (!handler->err_handler(skb, opt, type, code, offset, info)) 118 return 0; 119 120 return -ENOENT; 121 } 122 123 static int xfrm6_ipcomp_rcv(struct sk_buff *skb) 124 { 125 int ret; 126 struct xfrm6_protocol *handler; 127 128 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6 = NULL; 129 130 for_each_protocol_rcu(ipcomp6_handlers, handler) 131 if ((ret = handler->handler(skb)) != -EINVAL) 132 return ret; 133 134 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); 135 136 kfree_skb(skb); 137 return 0; 138 } 139 140 static int xfrm6_ipcomp_err(struct sk_buff *skb, struct inet6_skb_parm *opt, 141 u8 type, u8 code, int offset, __be32 info) 142 { 143 struct xfrm6_protocol *handler; 144 145 for_each_protocol_rcu(ipcomp6_handlers, handler) 146 if (!handler->err_handler(skb, opt, type, code, offset, info)) 147 return 0; 148 149 return -ENOENT; 150 } 151 152 static const struct inet6_protocol esp6_protocol = { 153 .handler = xfrm6_esp_rcv, 154 .err_handler = xfrm6_esp_err, 155 .flags = INET6_PROTO_NOPOLICY, 156 }; 157 158 static const struct inet6_protocol ah6_protocol = { 159 .handler = xfrm6_ah_rcv, 160 .err_handler = xfrm6_ah_err, 161 .flags = INET6_PROTO_NOPOLICY, 162 }; 163 164 static const struct inet6_protocol ipcomp6_protocol = { 165 .handler = xfrm6_ipcomp_rcv, 166 .err_handler = xfrm6_ipcomp_err, 167 .flags = INET6_PROTO_NOPOLICY, 168 }; 169 170 static const struct xfrm_input_afinfo xfrm6_input_afinfo = { 171 .family = AF_INET6, 172 .callback = xfrm6_rcv_cb, 173 }; 174 175 static inline const struct inet6_protocol *netproto(unsigned char protocol) 176 { 177 switch (protocol) { 178 case IPPROTO_ESP: 179 return &esp6_protocol; 180 case IPPROTO_AH: 181 return &ah6_protocol; 182 case IPPROTO_COMP: 183 return &ipcomp6_protocol; 184 } 185 186 return NULL; 187 } 188 189 int xfrm6_protocol_register(struct xfrm6_protocol *handler, 190 unsigned char protocol) 191 { 192 struct xfrm6_protocol __rcu **pprev; 193 struct xfrm6_protocol *t; 194 bool add_netproto = false; 195 int ret = -EEXIST; 196 int priority = handler->priority; 197 198 if (!proto_handlers(protocol) || !netproto(protocol)) 199 return -EINVAL; 200 201 mutex_lock(&xfrm6_protocol_mutex); 202 203 if (!rcu_dereference_protected(*proto_handlers(protocol), 204 lockdep_is_held(&xfrm6_protocol_mutex))) 205 add_netproto = true; 206 207 for (pprev = proto_handlers(protocol); 208 (t = rcu_dereference_protected(*pprev, 209 lockdep_is_held(&xfrm6_protocol_mutex))) != NULL; 210 pprev = &t->next) { 211 if (t->priority < priority) 212 break; 213 if (t->priority == priority) 214 goto err; 215 } 216 217 handler->next = *pprev; 218 rcu_assign_pointer(*pprev, handler); 219 220 ret = 0; 221 222 err: 223 mutex_unlock(&xfrm6_protocol_mutex); 224 225 if (add_netproto) { 226 if (inet6_add_protocol(netproto(protocol), protocol)) { 227 pr_err("%s: can't add protocol\n", __func__); 228 ret = -EAGAIN; 229 } 230 } 231 232 return ret; 233 } 234 EXPORT_SYMBOL(xfrm6_protocol_register); 235 236 int xfrm6_protocol_deregister(struct xfrm6_protocol *handler, 237 unsigned char protocol) 238 { 239 struct xfrm6_protocol __rcu **pprev; 240 struct xfrm6_protocol *t; 241 int ret = -ENOENT; 242 243 if (!proto_handlers(protocol) || !netproto(protocol)) 244 return -EINVAL; 245 246 mutex_lock(&xfrm6_protocol_mutex); 247 248 for (pprev = proto_handlers(protocol); 249 (t = rcu_dereference_protected(*pprev, 250 lockdep_is_held(&xfrm6_protocol_mutex))) != NULL; 251 pprev = &t->next) { 252 if (t == handler) { 253 *pprev = handler->next; 254 ret = 0; 255 break; 256 } 257 } 258 259 if (!rcu_dereference_protected(*proto_handlers(protocol), 260 lockdep_is_held(&xfrm6_protocol_mutex))) { 261 if (inet6_del_protocol(netproto(protocol), protocol) < 0) { 262 pr_err("%s: can't remove protocol\n", __func__); 263 ret = -EAGAIN; 264 } 265 } 266 267 mutex_unlock(&xfrm6_protocol_mutex); 268 269 synchronize_net(); 270 271 return ret; 272 } 273 EXPORT_SYMBOL(xfrm6_protocol_deregister); 274 275 int __init xfrm6_protocol_init(void) 276 { 277 return xfrm_input_register_afinfo(&xfrm6_input_afinfo); 278 } 279 280 void xfrm6_protocol_fini(void) 281 { 282 xfrm_input_unregister_afinfo(&xfrm6_input_afinfo); 283 } 284