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