linux/net/ipv4/gre.c
<<
>>
Prefs
   1/*
   2 *      GRE over IPv4 demultiplexer driver
   3 *
   4 *      Authors: Dmitry Kozlov (xeb@mail.ru)
   5 *
   6 *      This program is free software; you can redistribute it and/or
   7 *      modify it under the terms of the GNU General Public License
   8 *      as published by the Free Software Foundation; either version
   9 *      2 of the License, or (at your option) any later version.
  10 *
  11 */
  12
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/kmod.h>
  16#include <linux/skbuff.h>
  17#include <linux/in.h>
  18#include <linux/netdevice.h>
  19#include <linux/version.h>
  20#include <linux/spinlock.h>
  21#include <net/protocol.h>
  22#include <net/gre.h>
  23
  24
  25static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
  26static DEFINE_SPINLOCK(gre_proto_lock);
  27
  28int gre_add_protocol(const struct gre_protocol *proto, u8 version)
  29{
  30        if (version >= GREPROTO_MAX)
  31                goto err_out;
  32
  33        spin_lock(&gre_proto_lock);
  34        if (gre_proto[version])
  35                goto err_out_unlock;
  36
  37        rcu_assign_pointer(gre_proto[version], proto);
  38        spin_unlock(&gre_proto_lock);
  39        return 0;
  40
  41err_out_unlock:
  42        spin_unlock(&gre_proto_lock);
  43err_out:
  44        return -1;
  45}
  46EXPORT_SYMBOL_GPL(gre_add_protocol);
  47
  48int gre_del_protocol(const struct gre_protocol *proto, u8 version)
  49{
  50        if (version >= GREPROTO_MAX)
  51                goto err_out;
  52
  53        spin_lock(&gre_proto_lock);
  54        if (rcu_dereference_protected(gre_proto[version],
  55                        lockdep_is_held(&gre_proto_lock)) != proto)
  56                goto err_out_unlock;
  57        rcu_assign_pointer(gre_proto[version], NULL);
  58        spin_unlock(&gre_proto_lock);
  59        synchronize_rcu();
  60        return 0;
  61
  62err_out_unlock:
  63        spin_unlock(&gre_proto_lock);
  64err_out:
  65        return -1;
  66}
  67EXPORT_SYMBOL_GPL(gre_del_protocol);
  68
  69static int gre_rcv(struct sk_buff *skb)
  70{
  71        const struct gre_protocol *proto;
  72        u8 ver;
  73        int ret;
  74
  75        if (!pskb_may_pull(skb, 12))
  76                goto drop;
  77
  78        ver = skb->data[1]&0x7f;
  79        if (ver >= GREPROTO_MAX)
  80                goto drop;
  81
  82        rcu_read_lock();
  83        proto = rcu_dereference(gre_proto[ver]);
  84        if (!proto || !proto->handler)
  85                goto drop_unlock;
  86        ret = proto->handler(skb);
  87        rcu_read_unlock();
  88        return ret;
  89
  90drop_unlock:
  91        rcu_read_unlock();
  92drop:
  93        kfree_skb(skb);
  94        return NET_RX_DROP;
  95}
  96
  97static void gre_err(struct sk_buff *skb, u32 info)
  98{
  99        const struct gre_protocol *proto;
 100        u8 ver;
 101
 102        if (!pskb_may_pull(skb, 12))
 103                goto drop;
 104
 105        ver = skb->data[1]&0x7f;
 106        if (ver >= GREPROTO_MAX)
 107                goto drop;
 108
 109        rcu_read_lock();
 110        proto = rcu_dereference(gre_proto[ver]);
 111        if (!proto || !proto->err_handler)
 112                goto drop_unlock;
 113        proto->err_handler(skb, info);
 114        rcu_read_unlock();
 115        return;
 116
 117drop_unlock:
 118        rcu_read_unlock();
 119drop:
 120        kfree_skb(skb);
 121}
 122
 123static const struct net_protocol net_gre_protocol = {
 124        .handler     = gre_rcv,
 125        .err_handler = gre_err,
 126        .netns_ok    = 1,
 127};
 128
 129static int __init gre_init(void)
 130{
 131        pr_info("GRE over IPv4 demultiplexor driver");
 132
 133        if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
 134                pr_err("gre: can't add protocol\n");
 135                return -EAGAIN;
 136        }
 137
 138        return 0;
 139}
 140
 141static void __exit gre_exit(void)
 142{
 143        inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
 144}
 145
 146module_init(gre_init);
 147module_exit(gre_exit);
 148
 149MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
 150MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
 151MODULE_LICENSE("GPL");
 152
 153