diff options
author | Pravin B Shelar <pshelar@nicira.com> | 2013-06-17 20:49:38 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-19 21:07:40 -0400 |
commit | bda7bb46343647f68591366731295a0f3eea59ed (patch) | |
tree | 99fa502fe0439a7776227238bfc3a5b0d4dbe7b3 | |
parent | 20fd4d1f04da07d09192ad8ad366a70d5125bfaf (diff) |
gre: Allow multiple protocol listener for gre protocol.
Currently there is only one user is allowed to register for gre
protocol. Following patch adds de-multiplexer. So that multiple
modules can listen on gre protocol e.g. kernel gre devices and ovs.
Signed-off-by: Pravin B Shelar <pshelar@nicira.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/gre.h | 24 | ||||
-rw-r--r-- | net/ipv4/gre.c | 221 | ||||
-rw-r--r-- | net/ipv4/ip_gre.c | 173 |
3 files changed, 267 insertions, 151 deletions
diff --git a/include/net/gre.h b/include/net/gre.h index 9f03a390c826..c6ea0c72c605 100644 --- a/include/net/gre.h +++ b/include/net/gre.h | |||
@@ -7,6 +7,7 @@ | |||
7 | #define GREPROTO_CISCO 0 | 7 | #define GREPROTO_CISCO 0 |
8 | #define GREPROTO_PPTP 1 | 8 | #define GREPROTO_PPTP 1 |
9 | #define GREPROTO_MAX 2 | 9 | #define GREPROTO_MAX 2 |
10 | #define GRE_IP_PROTO_MAX 2 | ||
10 | 11 | ||
11 | struct gre_protocol { | 12 | struct gre_protocol { |
12 | int (*handler)(struct sk_buff *skb); | 13 | int (*handler)(struct sk_buff *skb); |
@@ -22,6 +23,29 @@ struct gre_base_hdr { | |||
22 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); | 23 | int gre_add_protocol(const struct gre_protocol *proto, u8 version); |
23 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); | 24 | int gre_del_protocol(const struct gre_protocol *proto, u8 version); |
24 | 25 | ||
26 | struct gre_cisco_protocol { | ||
27 | int (*handler)(struct sk_buff *skb, const struct tnl_ptk_info *tpi); | ||
28 | int (*err_handler)(struct sk_buff *skb, u32 info, | ||
29 | const struct tnl_ptk_info *tpi); | ||
30 | u8 priority; | ||
31 | }; | ||
32 | |||
33 | int gre_cisco_register(struct gre_cisco_protocol *proto); | ||
34 | int gre_cisco_unregister(struct gre_cisco_protocol *proto); | ||
35 | |||
36 | static inline int ip_gre_calc_hlen(__be16 o_flags) | ||
37 | { | ||
38 | int addend = 4; | ||
39 | |||
40 | if (o_flags&TUNNEL_CSUM) | ||
41 | addend += 4; | ||
42 | if (o_flags&TUNNEL_KEY) | ||
43 | addend += 4; | ||
44 | if (o_flags&TUNNEL_SEQ) | ||
45 | addend += 4; | ||
46 | return addend; | ||
47 | } | ||
48 | |||
25 | static inline __be16 gre_flags_to_tnl_flags(__be16 flags) | 49 | static inline __be16 gre_flags_to_tnl_flags(__be16 flags) |
26 | { | 50 | { |
27 | __be16 tflags = 0; | 51 | __be16 tflags = 0; |
diff --git a/net/ipv4/gre.c b/net/ipv4/gre.c index 1e294d510ac3..8b9a373890ab 100644 --- a/net/ipv4/gre.c +++ b/net/ipv4/gre.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | 13 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
14 | 14 | ||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/if.h> | ||
17 | #include <linux/icmp.h> | ||
16 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
17 | #include <linux/kmod.h> | 19 | #include <linux/kmod.h> |
18 | #include <linux/skbuff.h> | 20 | #include <linux/skbuff.h> |
@@ -24,8 +26,12 @@ | |||
24 | #include <net/protocol.h> | 26 | #include <net/protocol.h> |
25 | #include <net/gre.h> | 27 | #include <net/gre.h> |
26 | 28 | ||
29 | #include <net/icmp.h> | ||
30 | #include <net/route.h> | ||
31 | #include <net/xfrm.h> | ||
27 | 32 | ||
28 | 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]; | ||
29 | 35 | ||
30 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) | 36 | int gre_add_protocol(const struct gre_protocol *proto, u8 version) |
31 | { | 37 | { |
@@ -55,6 +61,173 @@ int gre_del_protocol(const struct gre_protocol *proto, u8 version) | |||
55 | } | 61 | } |
56 | EXPORT_SYMBOL_GPL(gre_del_protocol); | 62 | EXPORT_SYMBOL_GPL(gre_del_protocol); |
57 | 63 | ||
64 | static __sum16 check_checksum(struct sk_buff *skb) | ||
65 | { | ||
66 | __sum16 csum = 0; | ||
67 | |||
68 | switch (skb->ip_summed) { | ||
69 | case CHECKSUM_COMPLETE: | ||
70 | csum = csum_fold(skb->csum); | ||
71 | |||
72 | if (!csum) | ||
73 | break; | ||
74 | /* Fall through. */ | ||
75 | |||
76 | case CHECKSUM_NONE: | ||
77 | skb->csum = 0; | ||
78 | csum = __skb_checksum_complete(skb); | ||
79 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
80 | break; | ||
81 | } | ||
82 | |||
83 | return csum; | ||
84 | } | ||
85 | |||
86 | static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, | ||
87 | bool *csum_err) | ||
88 | { | ||
89 | unsigned int ip_hlen = ip_hdrlen(skb); | ||
90 | const struct gre_base_hdr *greh; | ||
91 | __be32 *options; | ||
92 | int hdr_len; | ||
93 | |||
94 | if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr)))) | ||
95 | return -EINVAL; | ||
96 | |||
97 | greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen); | ||
98 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) | ||
99 | return -EINVAL; | ||
100 | |||
101 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); | ||
102 | hdr_len = ip_gre_calc_hlen(tpi->flags); | ||
103 | |||
104 | if (!pskb_may_pull(skb, hdr_len)) | ||
105 | return -EINVAL; | ||
106 | |||
107 | greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen); | ||
108 | tpi->proto = greh->protocol; | ||
109 | |||
110 | options = (__be32 *)(greh + 1); | ||
111 | if (greh->flags & GRE_CSUM) { | ||
112 | if (check_checksum(skb)) { | ||
113 | *csum_err = true; | ||
114 | return -EINVAL; | ||
115 | } | ||
116 | options++; | ||
117 | } | ||
118 | |||
119 | if (greh->flags & GRE_KEY) { | ||
120 | tpi->key = *options; | ||
121 | options++; | ||
122 | } else | ||
123 | tpi->key = 0; | ||
124 | |||
125 | if (unlikely(greh->flags & GRE_SEQ)) { | ||
126 | tpi->seq = *options; | ||
127 | options++; | ||
128 | } else | ||
129 | tpi->seq = 0; | ||
130 | |||
131 | /* WCCP version 1 and 2 protocol decoding. | ||
132 | * - Change protocol to IP | ||
133 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header | ||
134 | */ | ||
135 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { | ||
136 | tpi->proto = htons(ETH_P_IP); | ||
137 | if ((*(u8 *)options & 0xF0) != 0x40) { | ||
138 | hdr_len += 4; | ||
139 | if (!pskb_may_pull(skb, hdr_len)) | ||
140 | return -EINVAL; | ||
141 | } | ||
142 | } | ||
143 | return 0; | ||
144 | } | ||
145 | |||
146 | static int gre_cisco_rcv(struct sk_buff *skb) | ||
147 | { | ||
148 | struct tnl_ptk_info tpi; | ||
149 | int i; | ||
150 | bool csum_err = false; | ||
151 | |||
152 | if (parse_gre_header(skb, &tpi, &csum_err) < 0) | ||
153 | goto drop; | ||
154 | |||
155 | rcu_read_lock(); | ||
156 | for (i = 0; i < GRE_IP_PROTO_MAX; i++) { | ||
157 | struct gre_cisco_protocol *proto; | ||
158 | int ret; | ||
159 | |||
160 | proto = rcu_dereference(gre_cisco_proto_list[i]); | ||
161 | if (!proto) | ||
162 | continue; | ||
163 | ret = proto->handler(skb, &tpi); | ||
164 | if (ret == PACKET_RCVD) { | ||
165 | rcu_read_unlock(); | ||
166 | return 0; | ||
167 | } | ||
168 | } | ||
169 | rcu_read_unlock(); | ||
170 | |||
171 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | ||
172 | drop: | ||
173 | kfree_skb(skb); | ||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static void gre_cisco_err(struct sk_buff *skb, u32 info) | ||
178 | { | ||
179 | /* All the routers (except for Linux) return only | ||
180 | * 8 bytes of packet payload. It means, that precise relaying of | ||
181 | * ICMP in the real Internet is absolutely infeasible. | ||
182 | * | ||
183 | * Moreover, Cisco "wise men" put GRE key to the third word | ||
184 | * in GRE header. It makes impossible maintaining even soft | ||
185 | * state for keyed | ||
186 | * GRE tunnels with enabled checksum. Tell them "thank you". | ||
187 | * | ||
188 | * Well, I wonder, rfc1812 was written by Cisco employee, | ||
189 | * what the hell these idiots break standards established | ||
190 | * by themselves??? | ||
191 | */ | ||
192 | |||
193 | const int type = icmp_hdr(skb)->type; | ||
194 | const int code = icmp_hdr(skb)->code; | ||
195 | struct tnl_ptk_info tpi; | ||
196 | bool csum_err = false; | ||
197 | int i; | ||
198 | |||
199 | if (parse_gre_header(skb, &tpi, &csum_err)) { | ||
200 | if (!csum_err) /* ignore csum errors. */ | ||
201 | return; | ||
202 | } | ||
203 | |||
204 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | ||
205 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, | ||
206 | skb->dev->ifindex, 0, IPPROTO_GRE, 0); | ||
207 | return; | ||
208 | } | ||
209 | if (type == ICMP_REDIRECT) { | ||
210 | ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0, | ||
211 | IPPROTO_GRE, 0); | ||
212 | return; | ||
213 | } | ||
214 | |||
215 | rcu_read_lock(); | ||
216 | for (i = 0; i < GRE_IP_PROTO_MAX; i++) { | ||
217 | struct gre_cisco_protocol *proto; | ||
218 | |||
219 | proto = rcu_dereference(gre_cisco_proto_list[i]); | ||
220 | if (!proto) | ||
221 | continue; | ||
222 | |||
223 | if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD) | ||
224 | goto out; | ||
225 | |||
226 | } | ||
227 | out: | ||
228 | rcu_read_unlock(); | ||
229 | } | ||
230 | |||
58 | static int gre_rcv(struct sk_buff *skb) | 231 | static int gre_rcv(struct sk_buff *skb) |
59 | { | 232 | { |
60 | const struct gre_protocol *proto; | 233 | const struct gre_protocol *proto; |
@@ -206,27 +379,68 @@ static const struct net_offload gre_offload = { | |||
206 | }, | 379 | }, |
207 | }; | 380 | }; |
208 | 381 | ||
382 | static const struct gre_protocol ipgre_protocol = { | ||
383 | .handler = gre_cisco_rcv, | ||
384 | .err_handler = gre_cisco_err, | ||
385 | }; | ||
386 | |||
387 | int gre_cisco_register(struct gre_cisco_protocol *newp) | ||
388 | { | ||
389 | struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **) | ||
390 | &gre_cisco_proto_list[newp->priority]; | ||
391 | |||
392 | return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY; | ||
393 | } | ||
394 | EXPORT_SYMBOL_GPL(gre_cisco_register); | ||
395 | |||
396 | int gre_cisco_unregister(struct gre_cisco_protocol *del_proto) | ||
397 | { | ||
398 | struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **) | ||
399 | &gre_cisco_proto_list[del_proto->priority]; | ||
400 | int ret; | ||
401 | |||
402 | ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL; | ||
403 | |||
404 | if (ret) | ||
405 | return ret; | ||
406 | |||
407 | synchronize_net(); | ||
408 | return 0; | ||
409 | } | ||
410 | EXPORT_SYMBOL_GPL(gre_cisco_unregister); | ||
411 | |||
209 | static int __init gre_init(void) | 412 | static int __init gre_init(void) |
210 | { | 413 | { |
211 | pr_info("GRE over IPv4 demultiplexor driver\n"); | 414 | pr_info("GRE over IPv4 demultiplexor driver\n"); |
212 | 415 | ||
213 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { | 416 | if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { |
214 | pr_err("can't add protocol\n"); | 417 | pr_err("can't add protocol\n"); |
215 | return -EAGAIN; | 418 | goto err; |
419 | } | ||
420 | |||
421 | if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) { | ||
422 | pr_info("%s: can't add ipgre handler\n", __func__); | ||
423 | goto err_gre; | ||
216 | } | 424 | } |
217 | 425 | ||
218 | if (inet_add_offload(&gre_offload, IPPROTO_GRE)) { | 426 | if (inet_add_offload(&gre_offload, IPPROTO_GRE)) { |
219 | pr_err("can't add protocol offload\n"); | 427 | pr_err("can't add protocol offload\n"); |
220 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | 428 | goto err_gso; |
221 | return -EAGAIN; | ||
222 | } | 429 | } |
223 | 430 | ||
224 | return 0; | 431 | return 0; |
432 | err_gso: | ||
433 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); | ||
434 | err_gre: | ||
435 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | ||
436 | err: | ||
437 | return -EAGAIN; | ||
225 | } | 438 | } |
226 | 439 | ||
227 | static void __exit gre_exit(void) | 440 | static void __exit gre_exit(void) |
228 | { | 441 | { |
229 | inet_del_offload(&gre_offload, IPPROTO_GRE); | 442 | inet_del_offload(&gre_offload, IPPROTO_GRE); |
443 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); | ||
230 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); | 444 | inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); |
231 | } | 445 | } |
232 | 446 | ||
@@ -236,4 +450,3 @@ module_exit(gre_exit); | |||
236 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); | 450 | MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver"); |
237 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); | 451 | MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)"); |
238 | MODULE_LICENSE("GPL"); | 452 | MODULE_LICENSE("GPL"); |
239 | |||
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index a982657d05e7..19863a81cea1 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c | |||
@@ -121,103 +121,8 @@ static int ipgre_tunnel_init(struct net_device *dev); | |||
121 | static int ipgre_net_id __read_mostly; | 121 | static int ipgre_net_id __read_mostly; |
122 | static int gre_tap_net_id __read_mostly; | 122 | static int gre_tap_net_id __read_mostly; |
123 | 123 | ||
124 | static __sum16 check_checksum(struct sk_buff *skb) | 124 | static int ipgre_err(struct sk_buff *skb, u32 info, |
125 | { | 125 | const struct tnl_ptk_info *tpi) |
126 | __sum16 csum = 0; | ||
127 | |||
128 | switch (skb->ip_summed) { | ||
129 | case CHECKSUM_COMPLETE: | ||
130 | csum = csum_fold(skb->csum); | ||
131 | |||
132 | if (!csum) | ||
133 | break; | ||
134 | /* Fall through. */ | ||
135 | |||
136 | case CHECKSUM_NONE: | ||
137 | skb->csum = 0; | ||
138 | csum = __skb_checksum_complete(skb); | ||
139 | skb->ip_summed = CHECKSUM_COMPLETE; | ||
140 | break; | ||
141 | } | ||
142 | |||
143 | return csum; | ||
144 | } | ||
145 | |||
146 | static int ip_gre_calc_hlen(__be16 o_flags) | ||
147 | { | ||
148 | int addend = 4; | ||
149 | |||
150 | if (o_flags&TUNNEL_CSUM) | ||
151 | addend += 4; | ||
152 | if (o_flags&TUNNEL_KEY) | ||
153 | addend += 4; | ||
154 | if (o_flags&TUNNEL_SEQ) | ||
155 | addend += 4; | ||
156 | return addend; | ||
157 | } | ||
158 | |||
159 | static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, | ||
160 | bool *csum_err, int *hdr_len) | ||
161 | { | ||
162 | unsigned int ip_hlen = ip_hdrlen(skb); | ||
163 | const struct gre_base_hdr *greh; | ||
164 | __be32 *options; | ||
165 | |||
166 | if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr)))) | ||
167 | return -EINVAL; | ||
168 | |||
169 | greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen); | ||
170 | if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) | ||
171 | return -EINVAL; | ||
172 | |||
173 | tpi->flags = gre_flags_to_tnl_flags(greh->flags); | ||
174 | *hdr_len = ip_gre_calc_hlen(tpi->flags); | ||
175 | |||
176 | if (!pskb_may_pull(skb, *hdr_len)) | ||
177 | return -EINVAL; | ||
178 | |||
179 | greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen); | ||
180 | |||
181 | tpi->proto = greh->protocol; | ||
182 | |||
183 | options = (__be32 *)(greh + 1); | ||
184 | if (greh->flags & GRE_CSUM) { | ||
185 | if (check_checksum(skb)) { | ||
186 | *csum_err = true; | ||
187 | return -EINVAL; | ||
188 | } | ||
189 | options++; | ||
190 | } | ||
191 | |||
192 | if (greh->flags & GRE_KEY) { | ||
193 | tpi->key = *options; | ||
194 | options++; | ||
195 | } else | ||
196 | tpi->key = 0; | ||
197 | |||
198 | if (unlikely(greh->flags & GRE_SEQ)) { | ||
199 | tpi->seq = *options; | ||
200 | options++; | ||
201 | } else | ||
202 | tpi->seq = 0; | ||
203 | |||
204 | /* WCCP version 1 and 2 protocol decoding. | ||
205 | * - Change protocol to IP | ||
206 | * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header | ||
207 | */ | ||
208 | if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { | ||
209 | tpi->proto = htons(ETH_P_IP); | ||
210 | if ((*(u8 *)options & 0xF0) != 0x40) { | ||
211 | *hdr_len += 4; | ||
212 | if (!pskb_may_pull(skb, *hdr_len)) | ||
213 | return -EINVAL; | ||
214 | } | ||
215 | } | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static void ipgre_err(struct sk_buff *skb, u32 info) | ||
221 | { | 126 | { |
222 | 127 | ||
223 | /* All the routers (except for Linux) return only | 128 | /* All the routers (except for Linux) return only |
@@ -239,26 +144,18 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
239 | const int type = icmp_hdr(skb)->type; | 144 | const int type = icmp_hdr(skb)->type; |
240 | const int code = icmp_hdr(skb)->code; | 145 | const int code = icmp_hdr(skb)->code; |
241 | struct ip_tunnel *t; | 146 | struct ip_tunnel *t; |
242 | struct tnl_ptk_info tpi; | ||
243 | int hdr_len; | ||
244 | bool csum_err = false; | ||
245 | |||
246 | if (parse_gre_header(skb, &tpi, &csum_err, &hdr_len)) { | ||
247 | if (!csum_err) /* ignore csum errors. */ | ||
248 | return; | ||
249 | } | ||
250 | 147 | ||
251 | switch (type) { | 148 | switch (type) { |
252 | default: | 149 | default: |
253 | case ICMP_PARAMETERPROB: | 150 | case ICMP_PARAMETERPROB: |
254 | return; | 151 | return PACKET_RCVD; |
255 | 152 | ||
256 | case ICMP_DEST_UNREACH: | 153 | case ICMP_DEST_UNREACH: |
257 | switch (code) { | 154 | switch (code) { |
258 | case ICMP_SR_FAILED: | 155 | case ICMP_SR_FAILED: |
259 | case ICMP_PORT_UNREACH: | 156 | case ICMP_PORT_UNREACH: |
260 | /* Impossible event. */ | 157 | /* Impossible event. */ |
261 | return; | 158 | return PACKET_RCVD; |
262 | default: | 159 | default: |
263 | /* All others are translated to HOST_UNREACH. | 160 | /* All others are translated to HOST_UNREACH. |
264 | rfc2003 contains "deep thoughts" about NET_UNREACH, | 161 | rfc2003 contains "deep thoughts" about NET_UNREACH, |
@@ -269,79 +166,61 @@ static void ipgre_err(struct sk_buff *skb, u32 info) | |||
269 | break; | 166 | break; |
270 | case ICMP_TIME_EXCEEDED: | 167 | case ICMP_TIME_EXCEEDED: |
271 | if (code != ICMP_EXC_TTL) | 168 | if (code != ICMP_EXC_TTL) |
272 | return; | 169 | return PACKET_RCVD; |
273 | break; | 170 | break; |
274 | 171 | ||
275 | case ICMP_REDIRECT: | 172 | case ICMP_REDIRECT: |
276 | break; | 173 | break; |
277 | } | 174 | } |
278 | 175 | ||
279 | if (tpi.proto == htons(ETH_P_TEB)) | 176 | if (tpi->proto == htons(ETH_P_TEB)) |
280 | itn = net_generic(net, gre_tap_net_id); | 177 | itn = net_generic(net, gre_tap_net_id); |
281 | else | 178 | else |
282 | itn = net_generic(net, ipgre_net_id); | 179 | itn = net_generic(net, ipgre_net_id); |
283 | 180 | ||
284 | iph = (const struct iphdr *)skb->data; | 181 | iph = (const struct iphdr *)skb->data; |
285 | t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi.flags, | 182 | t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, |
286 | iph->daddr, iph->saddr, tpi.key); | 183 | iph->daddr, iph->saddr, tpi->key); |
287 | 184 | ||
288 | if (t == NULL) | 185 | if (t == NULL) |
289 | return; | 186 | return PACKET_REJECT; |
290 | 187 | ||
291 | if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) { | ||
292 | ipv4_update_pmtu(skb, dev_net(skb->dev), info, | ||
293 | t->parms.link, 0, IPPROTO_GRE, 0); | ||
294 | return; | ||
295 | } | ||
296 | if (type == ICMP_REDIRECT) { | ||
297 | ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0, | ||
298 | IPPROTO_GRE, 0); | ||
299 | return; | ||
300 | } | ||
301 | if (t->parms.iph.daddr == 0 || | 188 | if (t->parms.iph.daddr == 0 || |
302 | ipv4_is_multicast(t->parms.iph.daddr)) | 189 | ipv4_is_multicast(t->parms.iph.daddr)) |
303 | return; | 190 | return PACKET_RCVD; |
304 | 191 | ||
305 | if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) | 192 | if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) |
306 | return; | 193 | return PACKET_RCVD; |
307 | 194 | ||
308 | if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) | 195 | if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO)) |
309 | t->err_count++; | 196 | t->err_count++; |
310 | else | 197 | else |
311 | t->err_count = 1; | 198 | t->err_count = 1; |
312 | t->err_time = jiffies; | 199 | t->err_time = jiffies; |
200 | return PACKET_RCVD; | ||
313 | } | 201 | } |
314 | 202 | ||
315 | static int ipgre_rcv(struct sk_buff *skb) | 203 | static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) |
316 | { | 204 | { |
317 | struct net *net = dev_net(skb->dev); | 205 | struct net *net = dev_net(skb->dev); |
318 | struct ip_tunnel_net *itn; | 206 | struct ip_tunnel_net *itn; |
319 | const struct iphdr *iph; | 207 | const struct iphdr *iph; |
320 | struct ip_tunnel *tunnel; | 208 | struct ip_tunnel *tunnel; |
321 | struct tnl_ptk_info tpi; | ||
322 | int hdr_len; | ||
323 | bool csum_err = false; | ||
324 | |||
325 | if (parse_gre_header(skb, &tpi, &csum_err, &hdr_len) < 0) | ||
326 | goto drop; | ||
327 | 209 | ||
328 | if (tpi.proto == htons(ETH_P_TEB)) | 210 | if (tpi->proto == htons(ETH_P_TEB)) |
329 | itn = net_generic(net, gre_tap_net_id); | 211 | itn = net_generic(net, gre_tap_net_id); |
330 | else | 212 | else |
331 | itn = net_generic(net, ipgre_net_id); | 213 | itn = net_generic(net, ipgre_net_id); |
332 | 214 | ||
333 | iph = ip_hdr(skb); | 215 | iph = ip_hdr(skb); |
334 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi.flags, | 216 | tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, |
335 | iph->saddr, iph->daddr, tpi.key); | 217 | iph->saddr, iph->daddr, tpi->key); |
336 | 218 | ||
337 | if (tunnel) { | 219 | if (tunnel) { |
338 | ip_tunnel_rcv(tunnel, skb, &tpi, log_ecn_error); | 220 | ip_tunnel_rcv(tunnel, skb, tpi, log_ecn_error); |
339 | return 0; | 221 | return PACKET_RCVD; |
340 | } | 222 | } |
341 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); | 223 | return PACKET_REJECT; |
342 | drop: | ||
343 | kfree_skb(skb); | ||
344 | return 0; | ||
345 | } | 224 | } |
346 | 225 | ||
347 | static struct sk_buff *handle_offloads(struct ip_tunnel *tunnel, struct sk_buff *skb) | 226 | static struct sk_buff *handle_offloads(struct ip_tunnel *tunnel, struct sk_buff *skb) |
@@ -708,9 +587,10 @@ static int ipgre_tunnel_init(struct net_device *dev) | |||
708 | return ip_tunnel_init(dev); | 587 | return ip_tunnel_init(dev); |
709 | } | 588 | } |
710 | 589 | ||
711 | static const struct gre_protocol ipgre_protocol = { | 590 | static struct gre_cisco_protocol ipgre_protocol = { |
712 | .handler = ipgre_rcv, | 591 | .handler = ipgre_rcv, |
713 | .err_handler = ipgre_err, | 592 | .err_handler = ipgre_err, |
593 | .priority = 0, | ||
714 | }; | 594 | }; |
715 | 595 | ||
716 | static int __net_init ipgre_init_net(struct net *net) | 596 | static int __net_init ipgre_init_net(struct net *net) |
@@ -978,7 +858,7 @@ static int __init ipgre_init(void) | |||
978 | if (err < 0) | 858 | if (err < 0) |
979 | goto pnet_tap_faied; | 859 | goto pnet_tap_faied; |
980 | 860 | ||
981 | err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO); | 861 | err = gre_cisco_register(&ipgre_protocol); |
982 | if (err < 0) { | 862 | if (err < 0) { |
983 | pr_info("%s: can't add protocol\n", __func__); | 863 | pr_info("%s: can't add protocol\n", __func__); |
984 | goto add_proto_failed; | 864 | goto add_proto_failed; |
@@ -997,7 +877,7 @@ static int __init ipgre_init(void) | |||
997 | tap_ops_failed: | 877 | tap_ops_failed: |
998 | rtnl_link_unregister(&ipgre_link_ops); | 878 | rtnl_link_unregister(&ipgre_link_ops); |
999 | rtnl_link_failed: | 879 | rtnl_link_failed: |
1000 | gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); | 880 | gre_cisco_unregister(&ipgre_protocol); |
1001 | add_proto_failed: | 881 | add_proto_failed: |
1002 | unregister_pernet_device(&ipgre_tap_net_ops); | 882 | unregister_pernet_device(&ipgre_tap_net_ops); |
1003 | pnet_tap_faied: | 883 | pnet_tap_faied: |
@@ -1009,8 +889,7 @@ static void __exit ipgre_fini(void) | |||
1009 | { | 889 | { |
1010 | rtnl_link_unregister(&ipgre_tap_ops); | 890 | rtnl_link_unregister(&ipgre_tap_ops); |
1011 | rtnl_link_unregister(&ipgre_link_ops); | 891 | rtnl_link_unregister(&ipgre_link_ops); |
1012 | if (gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) | 892 | gre_cisco_unregister(&ipgre_protocol); |
1013 | pr_info("%s: can't remove protocol\n", __func__); | ||
1014 | unregister_pernet_device(&ipgre_tap_net_ops); | 893 | unregister_pernet_device(&ipgre_tap_net_ops); |
1015 | unregister_pernet_device(&ipgre_net_ops); | 894 | unregister_pernet_device(&ipgre_net_ops); |
1016 | } | 895 | } |