linux/net/ipv4/xfrm4_protocol.c
<<
>>
Prefs
   1/* xfrm4_protocol.c - Generic xfrm protocol multiplexer.
   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/tunnel4.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 <net/icmp.h>
  21#include <net/ip.h>
  22#include <net/protocol.h>
  23#include <net/xfrm.h>
  24
  25static struct xfrm4_protocol __rcu *esp4_handlers __read_mostly;
  26static struct xfrm4_protocol __rcu *ah4_handlers __read_mostly;
  27static struct xfrm4_protocol __rcu *ipcomp4_handlers __read_mostly;
  28static DEFINE_MUTEX(xfrm4_protocol_mutex);
  29
  30static inline struct xfrm4_protocol __rcu **proto_handlers(u8 protocol)
  31{
  32        switch (protocol) {
  33        case IPPROTO_ESP:
  34                return &esp4_handlers;
  35        case IPPROTO_AH:
  36                return &ah4_handlers;
  37        case IPPROTO_COMP:
  38                return &ipcomp4_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
  49int xfrm4_rcv_cb(struct sk_buff *skb, u8 protocol, int err)
  50{
  51        int ret;
  52        struct xfrm4_protocol *handler;
  53        struct xfrm4_protocol __rcu **head = proto_handlers(protocol);
  54
  55        if (!head)
  56                return 0;
  57
  58        for_each_protocol_rcu(*head, handler)
  59                if ((ret = handler->cb_handler(skb, err)) <= 0)
  60                        return ret;
  61
  62        return 0;
  63}
  64EXPORT_SYMBOL(xfrm4_rcv_cb);
  65
  66int xfrm4_rcv_encap(struct sk_buff *skb, int nexthdr, __be32 spi,
  67                    int encap_type)
  68{
  69        int ret;
  70        struct xfrm4_protocol *handler;
  71        struct xfrm4_protocol __rcu **head = proto_handlers(nexthdr);
  72
  73        XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
  74        XFRM_SPI_SKB_CB(skb)->family = AF_INET;
  75        XFRM_SPI_SKB_CB(skb)->daddroff = offsetof(struct iphdr, daddr);
  76
  77        if (!head)
  78                goto out;
  79
  80        for_each_protocol_rcu(*head, handler)
  81                if ((ret = handler->input_handler(skb, nexthdr, spi, encap_type)) != -EINVAL)
  82                        return ret;
  83
  84out:
  85        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  86
  87        kfree_skb(skb);
  88        return 0;
  89}
  90EXPORT_SYMBOL(xfrm4_rcv_encap);
  91
  92static int xfrm4_esp_rcv(struct sk_buff *skb)
  93{
  94        int ret;
  95        struct xfrm4_protocol *handler;
  96
  97        XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
  98
  99        for_each_protocol_rcu(esp4_handlers, handler)
 100                if ((ret = handler->handler(skb)) != -EINVAL)
 101                        return ret;
 102
 103        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 104
 105        kfree_skb(skb);
 106        return 0;
 107}
 108
 109static void xfrm4_esp_err(struct sk_buff *skb, u32 info)
 110{
 111        struct xfrm4_protocol *handler;
 112
 113        for_each_protocol_rcu(esp4_handlers, handler)
 114                if (!handler->err_handler(skb, info))
 115                        break;
 116}
 117
 118static int xfrm4_ah_rcv(struct sk_buff *skb)
 119{
 120        int ret;
 121        struct xfrm4_protocol *handler;
 122
 123        XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
 124
 125        for_each_protocol_rcu(ah4_handlers, handler)
 126                if ((ret = handler->handler(skb)) != -EINVAL)
 127                        return ret;
 128
 129        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 130
 131        kfree_skb(skb);
 132        return 0;
 133}
 134
 135static void xfrm4_ah_err(struct sk_buff *skb, u32 info)
 136{
 137        struct xfrm4_protocol *handler;
 138
 139        for_each_protocol_rcu(ah4_handlers, handler)
 140                if (!handler->err_handler(skb, info))
 141                        break;
 142}
 143
 144static int xfrm4_ipcomp_rcv(struct sk_buff *skb)
 145{
 146        int ret;
 147        struct xfrm4_protocol *handler;
 148
 149        XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4 = NULL;
 150
 151        for_each_protocol_rcu(ipcomp4_handlers, handler)
 152                if ((ret = handler->handler(skb)) != -EINVAL)
 153                        return ret;
 154
 155        icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
 156
 157        kfree_skb(skb);
 158        return 0;
 159}
 160
 161static void xfrm4_ipcomp_err(struct sk_buff *skb, u32 info)
 162{
 163        struct xfrm4_protocol *handler;
 164
 165        for_each_protocol_rcu(ipcomp4_handlers, handler)
 166                if (!handler->err_handler(skb, info))
 167                        break;
 168}
 169
 170static const struct net_protocol esp4_protocol = {
 171        .handler        =       xfrm4_esp_rcv,
 172        .err_handler    =       xfrm4_esp_err,
 173        .no_policy      =       1,
 174        .netns_ok       =       1,
 175};
 176
 177static const struct net_protocol ah4_protocol = {
 178        .handler        =       xfrm4_ah_rcv,
 179        .err_handler    =       xfrm4_ah_err,
 180        .no_policy      =       1,
 181        .netns_ok       =       1,
 182};
 183
 184static const struct net_protocol ipcomp4_protocol = {
 185        .handler        =       xfrm4_ipcomp_rcv,
 186        .err_handler    =       xfrm4_ipcomp_err,
 187        .no_policy      =       1,
 188        .netns_ok       =       1,
 189};
 190
 191static struct xfrm_input_afinfo xfrm4_input_afinfo = {
 192        .family         =       AF_INET,
 193        .owner          =       THIS_MODULE,
 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);
 302