1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/skbuff.h>
6 #include <linux/netdevice.h>
7 #include <linux/version.h>
8 #include <linux/spinlock.h>
9 #include <net/protocol.h>
13 struct gre_protocol
*gre_proto
[GREPROTO_MAX
] ____cacheline_aligned_in_smp
;
14 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
15 static rwlock_t gre_proto_lock
=RW_LOCK_UNLOCKED
;
17 static DEFINE_SPINLOCK(gre_proto_lock
);
20 int gre_add_protocol(struct gre_protocol
*proto
, u8 version
)
24 if (version
>= GREPROTO_MAX
)
27 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
28 write_lock_bh(&gre_proto_lock
);
30 spin_lock(&gre_proto_lock
);
32 if (gre_proto
[version
]) {
35 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
36 gre_proto
[version
] = proto
;
38 rcu_assign_pointer(gre_proto
[version
], proto
);
42 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
43 write_unlock_bh(&gre_proto_lock
);
45 spin_unlock(&gre_proto_lock
);
51 int gre_del_protocol(struct gre_protocol
*proto
, u8 version
)
53 if (version
>= GREPROTO_MAX
)
56 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
57 write_lock_bh(&gre_proto_lock
);
59 spin_lock(&gre_proto_lock
);
61 if (gre_proto
[version
] == proto
)
62 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
63 gre_proto
[version
] = NULL
;
65 rcu_assign_pointer(gre_proto
[version
], NULL
);
69 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
70 write_unlock_bh(&gre_proto_lock
);
72 spin_unlock(&gre_proto_lock
);
78 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
79 write_unlock_bh(&gre_proto_lock
);
81 spin_unlock(&gre_proto_lock
);
87 static int gre_rcv(struct sk_buff
*skb
)
91 struct gre_protocol
*proto
;
93 if (!pskb_may_pull(skb
, 12))
96 ver
= skb
->data
[1]&0x7f;
97 if (ver
>= GREPROTO_MAX
)
100 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
101 read_lock(&gre_proto_lock
);
102 proto
= gre_proto
[ver
];
105 proto
= rcu_dereference(gre_proto
[ver
]);
107 if (!proto
|| !proto
->handler
)
110 ret
= proto
->handler(skb
);
112 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
113 read_unlock(&gre_proto_lock
);
121 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
122 read_unlock(&gre_proto_lock
);
131 static void gre_err(struct sk_buff
*skb
, u32 info
)
134 struct gre_protocol
*proto
;
136 if (!pskb_may_pull(skb
, 12))
139 ver
=skb
->data
[1]&0x7f;
140 if (ver
>=GREPROTO_MAX
)
143 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
144 read_lock(&gre_proto_lock
);
145 proto
= gre_proto
[ver
];
148 proto
= rcu_dereference(gre_proto
[ver
]);
150 if (!proto
|| !proto
->err_handler
)
153 proto
->err_handler(skb
, info
);
154 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
155 read_unlock(&gre_proto_lock
);
163 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
164 read_unlock(&gre_proto_lock
);
172 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
173 static struct inet_protocol net_gre_protocol
= {
175 .err_handler
= gre_err
,
176 .protocol
= IPPROTO_GRE
,
180 static struct net_protocol net_gre_protocol
= {
182 .err_handler
= gre_err
,
183 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)
189 static int __init
gre_init(void)
191 printk(KERN_INFO
"GRE over IPv4 demultiplexor driver\n");
193 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
194 inet_add_protocol(&net_gre_protocol
);
196 if (inet_add_protocol(&net_gre_protocol
, IPPROTO_GRE
) < 0) {
197 printk(KERN_INFO
"gre: can't add protocol\n");
204 static void __exit
gre_exit(void)
206 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
207 inet_del_protocol(&net_gre_protocol
);
209 inet_del_protocol(&net_gre_protocol
, IPPROTO_GRE
);
213 module_init(gre_init
);
214 module_exit(gre_exit
);
216 MODULE_DESCRIPTION("GRE over IPv4 demultiplexor driver");
217 MODULE_AUTHOR("Kozlov D. (xeb@mail.ru)");
218 MODULE_LICENSE("GPL");
219 EXPORT_SYMBOL_GPL(gre_add_protocol
);
220 EXPORT_SYMBOL_GPL(gre_del_protocol
);