Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v5.4-rc5 301 lines 6.6 kB view raw
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* xfrm4_protocol.c - Generic xfrm protocol multiplexer. 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/tunnel4.c 11 */ 12 13#include <linux/init.h> 14#include <linux/mutex.h> 15#include <linux/skbuff.h> 16#include <net/icmp.h> 17#include <net/ip.h> 18#include <net/protocol.h> 19#include <net/xfrm.h> 20 21static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly; 22static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly; 23static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly; 24static DEFINE_MUTEX(xfrm4_protocol_mutex); 25 26static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol) 27{ 28 switch (protocol) { 29 case IPPROTO_ESP: 30 return &esp4_handlers; 31 case IPPROTO_AH: 32 return &ah4_handlers; 33 case IPPROTO_COMP: 34 return &ipcomp4_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 45static int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err) 46{ 47 int ret; 48 struct xfrm4_protocol *handler; 49 struct xfrm4_protocol __rcu **head = proto_handlers(protocol); 50 51 if (!head) 52 return 0; 53 54 for_each_protocol_rcu(*head, handler) 55 if ((ret = handler->cb_handler(skb, err)) <= 0) 56 return ret; 57 58 return 0; 59} 60 61int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi, 62 int encap_type) 63{ 64 int ret; 65 struct xfrm4_protocol *handler; 66 struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr); 67 68 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; 69 XFRM_SPI_SKB_CB(skb)->family = AF_INET; 70 XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr); 71 72 if (!head) 73 goto out; 74 75 for_each_protocol_rcu(*head, handler) 76 if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL) 77 return ret; 78 79out: 80 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 81 82 kfree_skb(skb); 83 return 0; 84} 85EXPORT_SYMBOL(xfrm4_rcv_encap); 86 87static int xfrm4_esp_rcv(struct sk_buff *skb) 88{ 89 int ret; 90 struct xfrm4_protocol *handler; 91 92 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; 93 94 for_each_protocol_rcu(esp4_handlers, handler) 95 if ((ret = handler->handler(skb)) != -EINVAL) 96 return ret; 97 98 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 99 100 kfree_skb(skb); 101 return 0; 102} 103 104static int xfrm4_esp_err(struct sk_buff *skb, u32 info) 105{ 106 struct xfrm4_protocol *handler; 107 108 for_each_protocol_rcu(esp4_handlers, handler) 109 if (!handler->err_handler(skb, info)) 110 return 0; 111 112 return -ENOENT; 113} 114 115static int xfrm4_ah_rcv(struct sk_buff *skb) 116{ 117 int ret; 118 struct xfrm4_protocol *handler; 119 120 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; 121 122 for_each_protocol_rcu(ah4_handlers, handler) 123 if ((ret = handler->handler(skb)) != -EINVAL) 124 return ret; 125 126 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 127 128 kfree_skb(skb); 129 return 0; 130} 131 132static int xfrm4_ah_err(struct sk_buff *skb, u32 info) 133{ 134 struct xfrm4_protocol *handler; 135 136 for_each_protocol_rcu(ah4_handlers, handler) 137 if (!handler->err_handler(skb, info)) 138 return 0; 139 140 return -ENOENT; 141} 142 143static int xfrm4_ipcomp_rcv(struct sk_buff *skb) 144{ 145 int ret; 146 struct xfrm4_protocol *handler; 147 148 XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL; 149 150 for_each_protocol_rcu(ipcomp4_handlers, handler) 151 if ((ret = handler->handler(skb)) != -EINVAL) 152 return ret; 153 154 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); 155 156 kfree_skb(skb); 157 return 0; 158} 159 160static int xfrm4_ipcomp_err(struct sk_buff *skb, u32 info) 161{ 162 struct xfrm4_protocol *handler; 163 164 for_each_protocol_rcu(ipcomp4_handlers, handler) 165 if (!handler->err_handler(skb, info)) 166 return 0; 167 168 return -ENOENT; 169} 170 171static const struct net_protocol esp4_protocol = { 172 .handler = xfrm4_esp_rcv, 173 .err_handler = xfrm4_esp_err, 174 .no_policy = 1, 175 .netns_ok = 1, 176}; 177 178static const struct net_protocol ah4_protocol = { 179 .handler = xfrm4_ah_rcv, 180 .err_handler = xfrm4_ah_err, 181 .no_policy = 1, 182 .netns_ok = 1, 183}; 184 185static const struct net_protocol ipcomp4_protocol = { 186 .handler = xfrm4_ipcomp_rcv, 187 .err_handler = xfrm4_ipcomp_err, 188 .no_policy = 1, 189 .netns_ok = 1, 190}; 191 192static const struct xfrm_input_afinfo xfrm4_input_afinfo = { 193 .family = AF_INET, 194 .callback = xfrm4_rcv_cb, 195}; 196 197static inline const struct net_protocol *netproto(unsigned char protocol) 198{ 199 switch (protocol) { 200 case IPPROTO_ESP: 201 return &esp4_protocol; 202 case IPPROTO_AH: 203 return &ah4_protocol; 204 case IPPROTO_COMP: 205 return &ipcomp4_protocol; 206 } 207 208 return NULL; 209} 210 211int xfrm4_protocol_register(struct xfrm4_protocol *handler, 212 unsigned char protocol) 213{ 214 struct xfrm4_protocol __rcu **pprev; 215 struct xfrm4_protocol *t; 216 bool add_netproto = false; 217 int ret = -EEXIST; 218 int priority = handler->priority; 219 220 if (!proto_handlers(protocol) || !netproto(protocol)) 221 return -EINVAL; 222 223 mutex_lock(&xfrm4_protocol_mutex); 224 225 if (!rcu_dereference_protected(*proto_handlers(protocol), 226 lockdep_is_held(&xfrm4_protocol_mutex))) 227 add_netproto = true; 228 229 for (pprev = proto_handlers(protocol); 230 (t = rcu_dereference_protected(*pprev, 231 lockdep_is_held(&xfrm4_protocol_mutex))) != NULL; 232 pprev = &t->next) { 233 if (t->priority < priority) 234 break; 235 if (t->priority == priority) 236 goto err; 237 } 238 239 handler->next = *pprev; 240 rcu_assign_pointer(*pprev, handler); 241 242 ret = 0; 243 244err: 245 mutex_unlock(&xfrm4_protocol_mutex); 246 247 if (add_netproto) { 248 if (inet_add_protocol(netproto(protocol), protocol)) { 249 pr_err("%s: can't add protocol\n", __func__); 250 ret = -EAGAIN; 251 } 252 } 253 254 return ret; 255} 256EXPORT_SYMBOL(xfrm4_protocol_register); 257 258int xfrm4_protocol_deregister(struct xfrm4_protocol *handler, 259 unsigned char protocol) 260{ 261 struct xfrm4_protocol __rcu **pprev; 262 struct xfrm4_protocol *t; 263 int ret = -ENOENT; 264 265 if (!proto_handlers(protocol) || !netproto(protocol)) 266 return -EINVAL; 267 268 mutex_lock(&xfrm4_protocol_mutex); 269 270 for (pprev = proto_handlers(protocol); 271 (t = rcu_dereference_protected(*pprev, 272 lockdep_is_held(&xfrm4_protocol_mutex))) != NULL; 273 pprev = &t->next) { 274 if (t == handler) { 275 *pprev = handler->next; 276 ret = 0; 277 break; 278 } 279 } 280 281 if (!rcu_dereference_protected(*proto_handlers(protocol), 282 lockdep_is_held(&xfrm4_protocol_mutex))) { 283 if (inet_del_protocol(netproto(protocol), protocol) < 0) { 284 pr_err("%s: can't remove protocol\n", __func__); 285 ret = -EAGAIN; 286 } 287 } 288 289 mutex_unlock(&xfrm4_protocol_mutex); 290 291 synchronize_net(); 292 293 return ret; 294} 295EXPORT_SYMBOL(xfrm4_protocol_deregister); 296 297void __init xfrm4_protocol_init(void) 298{ 299 xfrm_input_register_afinfo(&xfrm4_input_afinfo); 300} 301EXPORT_SYMBOL(xfrm4_protocol_init);