diff options
Diffstat (limited to 'net/ipv4/gre_demux.c')
-rw-r--r-- | net/ipv4/gre_demux.c | 235 |
1 files changed, 1 insertions, 234 deletions
diff --git a/net/ipv4/gre_demux.c b/net/ipv4/gre_demux.c index 4a7b5b2a1ce3..d9c552a721fc 100644 --- a/net/ipv4/gre_demux.c +++ b/net/ipv4/gre_demux.c | |||
@@ -31,7 +31,6 @@ | |||
31 | #include <net/xfrm.h> | 31 | #include <net/xfrm.h> |
32 | 32 | ||
33 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; | 33 | static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; |
34 | static struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX]; | ||
35 | 34 | ||
36 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) | 35 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) |
37 | { | 36 | { |
@@ -61,197 +60,6 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version) | |||
61 | } | 60 | } |
62 | EXPORT_SYMBOL_GPL(gre_del_protocol); | 61 | EXPORT_SYMBOL_GPL(gre_del_protocol); |
63 | 62 | ||
64 | void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, | ||
65 | int hdr_len) | ||
66 | { | ||
67 | struct gre_base_hdr *greh; | ||
68 | |||
69 | skb_push(skb, hdr_len); | ||
70 | |||
71 | skb_reset_transport_header(skb); | ||
72 | greh = (struct gre_base_hdr *)skb->data; | ||
73 | greh->flags = tnl_flags_to_gre_flags(tpi->flags); | ||
74 | greh->protocol = tpi->proto; | ||
75 | |||
76 | if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) { | ||
77 | __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); | ||
78 | |||
79 | if (tpi->flags&TUNNEL_SEQ) { | ||
80 | *ptr = tpi->seq; | ||
81 | ptr--; | ||
82 | } | ||
83 | if (tpi->flags&TUNNEL_KEY) { | ||
84 | *ptr = tpi->key; | ||
85 | ptr--; | ||
86 | } | ||
87 | if (tpi->flags&TUNNEL_CSUM && | ||
88 | !(skb_shinfo(skb)->gso_type & | ||
89 | (SKB_GSO_GRE|SKB_GSO_GRE_CSUM))) { | ||
90 | *ptr = 0; | ||
91 | *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0, | ||
92 | skb->len, 0)); | ||
93 | } | ||
94 | } | ||
95 | } | ||
96 | EXPORT_SYMBOL_GPL(gre_build_header); | ||
97 | |||
98 | static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, | ||
99 | bool *csum_err) | ||
100 | { | ||
101 | const struct gre_base_hdr *greh; | ||
102 | __be32 *options; | ||
103 | int hdr_len; | ||
104 | |||
105 | if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr)))) | ||
106 | return -EINVAL; | ||
107 | |||
108 | greh = (struct gre_base_hdr *)skb_transport_header(skb); | ||
109 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) | ||
110 | return -EINVAL; | ||
111 | |||
112 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); | ||
113 | hdr_len = ip_gre_calc_hlen(tpi->flags); | ||
114 | |||
115 | if (!pskb_may_pull(skb, hdr_len)) | ||
116 | return -EINVAL; | ||
117 | |||
118 | greh = (struct gre_base_hdr *)skb_transport_header(skb); | ||
119 | tpi->proto = greh->protocol; | ||
120 | |||
121 | options = (__be32 *)(greh + 1); | ||
122 | if (greh->flags & GRE_CSUM) { | ||
123 | if (skb_checksum_simple_validate(skb)) { | ||
124 | *csum_err = true; | ||
125 | return -EINVAL; | ||
126 | } | ||
127 | |||
128 | skb_checksum_try_convert(skb, IPPROTO_GRE, 0, | ||
129 | null_compute_pseudo); | ||
130 | |||
131 | options++; | ||
132 | } | ||
133 | |||
134 | if (greh->flags & GRE_KEY) { | ||
135 | tpi->key = *options; | ||
136 | options++; | ||
137 | } else | ||
138 | tpi->key = 0; | ||
139 | |||
140 | if (unlikely(greh->flags & GRE_SEQ)) { | ||
141 | tpi->seq = *options; | ||
142 | options++; | ||
143 | } else | ||
144 | tpi->seq = 0; | ||
145 | |||
146 | /* WCCP version 1 and 2 protocol decoding. | ||
147 | * - Change protocol to IP | ||
148 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header | ||
149 | */ | ||
150 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { | ||
151 | tpi->proto = htons(ETH_P_IP); | ||
152 | if ((*(u8 *)options & 0xF0) != 0x40) { | ||
153 | hdr_len += 4; | ||
154 | if (!pskb_may_pull(skb, hdr_len)) | ||
155 | return -EINVAL; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | return iptunnel_pull_header(skb, hdr_len, tpi->proto); | ||
160 | } | ||
161 | |||
162 | static int gre_cisco_rcv(struct sk_buff *skb) | ||
163 | { | ||
164 | struct tnl_ptk_info tpi; | ||
165 | int i; | ||
166 | bool csum_err = false; | ||
167 | |||
168 | #ifdef CONFIG_NET_IPGRE_BROADCAST | ||
169 | if (ipv4_is_multicast(ip_hdr(skb)->daddr)) { | ||
170 | /* Looped back packet, drop it! */ | ||
171 | if (rt_is_output_route(skb_rtable(skb))) | ||
172 | goto drop; | ||
173 | } | ||
174 | #endif | ||
175 | |||
176 | if (parse_gre_header(skb, &tpi, &csum_err) < 0) | ||
177 | goto drop; | ||
178 | |||
179 | rcu_read_lock(); | ||
180 | for (i = 0; i < GRE_IP_PROTO_MAX; i++) { | ||
181 | struct gre_cisco_protocol *proto; | ||
182 | int ret; | ||
183 | |||
184 | proto = rcu_dereference(gre_cisco_proto_list[i]); | ||
185 | if (!proto) | ||
186 | continue; | ||
187 | ret = proto->handler(skb, &tpi); | ||
188 | if (ret == PACKET_RCVD) { | ||
189 | rcu_read_unlock(); | ||
190 | return 0; | ||
191 | } | ||
192 | } | ||
193 | rcu_read_unlock(); | ||
194 | |||
195 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | ||
196 | drop: | ||
197 | kfree_skb(skb); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static void gre_cisco_err(struct sk_buff *skb, u32 info) | ||
202 | { | ||
203 | /* All the routers (except for Linux) return only | ||
204 | * 8 bytes of packet payload. It means, that precise relaying of | ||
205 | * ICMP in the real Internet is absolutely infeasible. | ||
206 | * | ||
207 | * Moreover, Cisco "wise men" put GRE key to the third word | ||
208 | * in GRE header. It makes impossible maintaining even soft | ||
209 | * state for keyed | ||
210 | * GRE tunnels with enabled checksum. Tell them "thank you". | ||
211 | * | ||
212 | * Well, I wonder, rfc1812 was written by Cisco employee, | ||
213 | * what the hell these idiots break standards established | ||
214 | * by themselves??? | ||
215 | */ | ||
216 | |||
217 | const int type = icmp_hdr(skb)->type; | ||
218 | const int code = icmp_hdr(skb)->code; | ||
219 | struct tnl_ptk_info tpi; | ||
220 | bool csum_err = false; | ||
221 | int i; | ||
222 | |||
223 | if (parse_gre_header(skb, &tpi, &csum_err)) { | ||
224 | if (!csum_err) /* ignore csum errors. */ | ||
225 | return; | ||
226 | } | ||
227 | |||
228 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | ||
229 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, | ||
230 | skb->dev->ifindex, 0, IPPROTO_GRE, 0); | ||
231 | return; | ||
232 | } | ||
233 | if (type == ICMP_REDIRECT) { | ||
234 | ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0, | ||
235 | IPPROTO_GRE, 0); | ||
236 | return; | ||
237 | } | ||
238 | |||
239 | rcu_read_lock(); | ||
240 | for (i = 0; i < GRE_IP_PROTO_MAX; i++) { | ||
241 | struct gre_cisco_protocol *proto; | ||
242 | |||
243 | proto = rcu_dereference(gre_cisco_proto_list[i]); | ||
244 | if (!proto) | ||
245 | continue; | ||
246 | |||
247 | if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD) | ||
248 | goto out; | ||
249 | |||
250 | } | ||
251 | out: | ||
252 | rcu_read_unlock(); | ||
253 | } | ||
254 | |||
255 | static int gre_rcv(struct sk_buff *skb) | 63 | static int gre_rcv(struct sk_buff *skb) |
256 | { | 64 | { |
257 | const struct gre_protocol *proto; | 65 | const struct gre_protocol *proto; |
@@ -302,60 +110,19 @@ static const struct net_protocol net_gre_protocol = { | |||
302 | .netns_ok = 1, | 110 | .netns_ok = 1, |
303 | }; | 111 | }; |
304 | 112 | ||
305 | static const struct gre_protocol ipgre_protocol = { | ||
306 | .handler = gre_cisco_rcv, | ||
307 | .err_handler = gre_cisco_err, | ||
308 | }; | ||
309 | |||
310 | int gre_cisco_register(struct gre_cisco_protocol *newp) | ||
311 | { | ||
312 | struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **) | ||
313 | &gre_cisco_proto_list[newp->priority]; | ||
314 | |||
315 | return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY; | ||
316 | } | ||
317 | EXPORT_SYMBOL_GPL(gre_cisco_register); | ||
318 | |||
319 | int gre_cisco_unregister(struct gre_cisco_protocol *del_proto) | ||
320 | { | ||
321 | struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **) | ||
322 | &gre_cisco_proto_list[del_proto->priority]; | ||
323 | int ret; | ||
324 | |||
325 | ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL; | ||
326 | |||
327 | if (ret) | ||
328 | return ret; | ||
329 | |||
330 | synchronize_net(); | ||
331 | return 0; | ||
332 | } | ||
333 | EXPORT_SYMBOL_GPL(gre_cisco_unregister); | ||
334 | |||
335 | static int __init gre_init(void) | 113 | static int __init gre_init(void) |
336 | { | 114 | { |
337 | pr_info("GRE over IPv4 demultiplexor driver\n"); | 115 | pr_info("GRE over IPv4 demultiplexor driver\n"); |
338 | 116 | ||
339 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { | 117 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { |
340 | pr_err("can't add protocol\n"); | 118 | pr_err("can't add protocol\n"); |
341 | goto err; | 119 | return -EAGAIN; |
342 | } | ||
343 | |||
344 | if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) { | ||
345 | pr_info("%s: can't add ipgre handler\n", __func__); | ||
346 | goto err_gre; | ||
347 | } | 120 | } |
348 | |||
349 | return 0; | 121 | return 0; |
350 | err_gre: | ||
351 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | ||
352 | err: | ||
353 | return -EAGAIN; | ||
354 | } | 122 | } |
355 | 123 | ||
356 | static void __exit gre_exit(void) | 124 | static void __exit gre_exit(void) |
357 | { | 125 | { |
358 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); | ||
359 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | 126 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); |
360 | } | 127 | } |
361 | 128 | ||