NETFILTER: remove unnecessary goto statement for error recovery
[tomato.git] / release / src-rt / linux / linux-2.6 / net / ipv4 / gre.c
blobaf1531ff6d2f74df652534cf9147cb0126b73edc
1 #include <linux/module.h>
2 #include <linux/kernel.h>
3 #include <linux/init.h>
4 #include <linux/skbuff.h>
5 #include <linux/in.h>
6 #include <linux/netdevice.h>
7 #include <linux/version.h>
8 #include <linux/spinlock.h>
9 #include <net/protocol.h>
11 #include <net/gre.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;
16 #else
17 static DEFINE_SPINLOCK(gre_proto_lock);
18 #endif
20 int gre_add_protocol(struct gre_protocol *proto, u8 version)
22 int ret;
24 if (version >= GREPROTO_MAX)
25 return -EINVAL;
27 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
28 write_lock_bh(&gre_proto_lock);
29 #else
30 spin_lock(&gre_proto_lock);
31 #endif
32 if (gre_proto[version]) {
33 ret = -EAGAIN;
34 } else {
35 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
36 gre_proto[version] = proto;
37 #else
38 rcu_assign_pointer(gre_proto[version], proto);
39 #endif
40 ret = 0;
42 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
43 write_unlock_bh(&gre_proto_lock);
44 #else
45 spin_unlock(&gre_proto_lock);
46 #endif
48 return ret;
51 int gre_del_protocol(struct gre_protocol *proto, u8 version)
53 if (version >= GREPROTO_MAX)
54 goto out_err;
56 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
57 write_lock_bh(&gre_proto_lock);
58 #else
59 spin_lock(&gre_proto_lock);
60 #endif
61 if (gre_proto[version] == proto)
62 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
63 gre_proto[version] = NULL;
64 #else
65 rcu_assign_pointer(gre_proto[version], NULL);
66 #endif
67 else
68 goto out_err_unlock;
69 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
70 write_unlock_bh(&gre_proto_lock);
71 #else
72 spin_unlock(&gre_proto_lock);
73 synchronize_rcu();
74 #endif
75 return 0;
77 out_err_unlock:
78 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
79 write_unlock_bh(&gre_proto_lock);
80 #else
81 spin_unlock(&gre_proto_lock);
82 #endif
83 out_err:
84 return -EINVAL;
87 static int gre_rcv(struct sk_buff *skb)
89 u8 ver;
90 int ret;
91 struct gre_protocol *proto;
93 if (!pskb_may_pull(skb, 12))
94 goto drop_nolock;
96 ver = skb->data[1]&0x7f;
97 if (ver >= GREPROTO_MAX)
98 goto drop_nolock;
100 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
101 read_lock(&gre_proto_lock);
102 proto = gre_proto[ver];
103 #else
104 rcu_read_lock();
105 proto = rcu_dereference(gre_proto[ver]);
106 #endif
107 if (!proto || !proto->handler)
108 goto drop;
110 ret = proto->handler(skb);
112 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
113 read_unlock(&gre_proto_lock);
114 #else
115 rcu_read_unlock();
116 #endif
118 return ret;
120 drop:
121 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
122 read_unlock(&gre_proto_lock);
123 #else
124 rcu_read_unlock();
125 #endif
126 drop_nolock:
127 kfree_skb(skb);
128 return NET_RX_DROP;
131 static void gre_err(struct sk_buff *skb, u32 info)
133 u8 ver;
134 struct gre_protocol *proto;
136 if (!pskb_may_pull(skb, 12))
137 goto drop_nolock;
139 ver=skb->data[1]&0x7f;
140 if (ver>=GREPROTO_MAX)
141 goto drop_nolock;
143 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
144 read_lock(&gre_proto_lock);
145 proto = gre_proto[ver];
146 #else
147 rcu_read_lock();
148 proto = rcu_dereference(gre_proto[ver]);
149 #endif
150 if (!proto || !proto->err_handler)
151 goto drop;
153 proto->err_handler(skb, info);
154 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
155 read_unlock(&gre_proto_lock);
156 #else
157 rcu_read_unlock();
158 #endif
160 return;
162 drop:
163 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
164 read_unlock(&gre_proto_lock);
165 #else
166 rcu_read_unlock();
167 #endif
168 drop_nolock:
169 kfree_skb(skb);
172 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
173 static struct inet_protocol net_gre_protocol = {
174 .handler = gre_rcv,
175 .err_handler = gre_err,
176 .protocol = IPPROTO_GRE,
177 .name = "GRE",
179 #else
180 static struct net_protocol net_gre_protocol = {
181 .handler = gre_rcv,
182 .err_handler = gre_err,
183 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,24)
184 .netns_ok = 1,
185 #endif
187 #endif
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);
195 #else
196 if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
197 printk(KERN_INFO "gre: can't add protocol\n");
198 return -EAGAIN;
200 #endif
201 return 0;
204 static void __exit gre_exit(void)
206 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
207 inet_del_protocol(&net_gre_protocol);
208 #else
209 inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
210 #endif
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);