Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/ipv4/gre.c
15109 views
1
/*
2
* GRE over IPv4 demultiplexer driver
3
*
4
* Authors: Dmitry Kozlov ([email protected])
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
25
static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
26
static DEFINE_SPINLOCK(gre_proto_lock);
27
28
int 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
41
err_out_unlock:
42
spin_unlock(&gre_proto_lock);
43
err_out:
44
return -1;
45
}
46
EXPORT_SYMBOL_GPL(gre_add_protocol);
47
48
int 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
62
err_out_unlock:
63
spin_unlock(&gre_proto_lock);
64
err_out:
65
return -1;
66
}
67
EXPORT_SYMBOL_GPL(gre_del_protocol);
68
69
static 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
90
drop_unlock:
91
rcu_read_unlock();
92
drop:
93
kfree_skb(skb);
94
return NET_RX_DROP;
95
}
96
97
static 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
117
drop_unlock:
118
rcu_read_unlock();
119
drop:
120
kfree_skb(skb);
121
}
122
123
static const struct net_protocol net_gre_protocol = {
124
.handler = gre_rcv,
125
.err_handler = gre_err,
126
.netns_ok = 1,
127
};
128
129
static 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
141
static void __exit gre_exit(void)
142
{
143
inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
144
}
145
146
module_init(gre_init);
147
module_exit(gre_exit);
148
149
MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
150
MODULE_AUTHOR("D. Kozlov ([email protected])");
151
MODULE_LICENSE("GPL");
152
153
154