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