root/net/ipv6/xfrm6_protocol.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. proto_handlers
  2. xfrm6_rcv_cb
  3. xfrm6_esp_rcv
  4. xfrm6_esp_err
  5. xfrm6_ah_rcv
  6. xfrm6_ah_err
  7. xfrm6_ipcomp_rcv
  8. xfrm6_ipcomp_err
  9. netproto
  10. xfrm6_protocol_register
  11. xfrm6_protocol_deregister
  12. xfrm6_protocol_init
  13. xfrm6_protocol_fini

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

/* [<][>][^][v][top][bottom][index][help] */