root/net/ipv4/xfrm4_protocol.c

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

DEFINITIONS

This source file includes following definitions.
  1. proto_handlers
  2. xfrm4_rcv_cb
  3. xfrm4_rcv_encap
  4. xfrm4_esp_rcv
  5. xfrm4_esp_err
  6. xfrm4_ah_rcv
  7. xfrm4_ah_err
  8. xfrm4_ipcomp_rcv
  9. xfrm4_ipcomp_err
  10. netproto
  11. xfrm4_protocol_register
  12. xfrm4_protocol_deregister
  13. xfrm4_protocol_init

   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 
  21 static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly;
  22 static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly;
  23 static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly;
  24 static DEFINE_MUTEX(xfrm4_protocol_mutex);
  25 
  26 static 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 
  45 static 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 
  61 int 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 
  79 out:
  80         icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  81 
  82         kfree_skb(skb);
  83         return 0;
  84 }
  85 EXPORT_SYMBOL(xfrm4_rcv_encap);
  86 
  87 static 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 
 104 static 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 
 115 static 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 
 132 static 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 
 143 static 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 
 160 static 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 
 171 static 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 
 178 static 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 
 185 static 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 
 192 static const struct xfrm_input_afinfo xfrm4_input_afinfo = {
 193         .family         =       AF_INET,
 194         .callback       =       xfrm4_rcv_cb,
 195 };
 196 
 197 static 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 
 211 int 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 
 244 err:
 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 }
 256 EXPORT_SYMBOL(xfrm4_protocol_register);
 257 
 258 int 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 }
 295 EXPORT_SYMBOL(xfrm4_protocol_deregister);
 296 
 297 void __init xfrm4_protocol_init(void)
 298 {
 299         xfrm_input_register_afinfo(&xfrm4_input_afinfo);
 300 }
 301 EXPORT_SYMBOL(xfrm4_protocol_init);

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