diff options
Diffstat (limited to 'net/ipv4/ip_gre.c')
-rw-r--r-- | net/ipv4/ip_gre.c | 173 |
1 files changed, 26 insertions, 147 deletions
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 | } |