aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2012-07-12 00:27:49 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-12 00:27:49 -0400
commit55be7a9c6074f749d617a7fc1914c9a23505438c (patch)
tree507268878abc1c5f5476823264b6f9f8acefa205 /net
parentb42597e2f36e2043756aa7462faddf630962f061 (diff)
ipv4: Add redirect support to all protocol icmp error handlers.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/dccp/ipv4.c11
-rw-r--r--net/ipv4/ah4.c18
-rw-r--r--net/ipv4/esp4.c18
-rw-r--r--net/ipv4/ip_gre.c9
-rw-r--r--net/ipv4/ipcomp.c18
-rw-r--r--net/ipv4/ipip.c9
-rw-r--r--net/ipv4/ping.c1
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/tcp_ipv4.c11
-rw-r--r--net/ipv4/udp.c3
-rw-r--r--net/ipv4/xfrm4_policy.c10
-rw-r--r--net/sctp/input.c16
12 files changed, 110 insertions, 16 deletions
diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c
index 3eb76b5f221a..8f41a3190858 100644
--- a/net/dccp/ipv4.c
+++ b/net/dccp/ipv4.c
@@ -195,6 +195,14 @@ static inline void dccp_do_pmtu_discovery(struct sock *sk,
195 } /* else let the usual retransmit timer handle it */ 195 } /* else let the usual retransmit timer handle it */
196} 196}
197 197
198static void dccp_do_redirect(struct sk_buff *skb, struct sock *sk)
199{
200 struct dst_entry *dst = __sk_dst_check(sk, 0);
201
202 if (dst && dst->ops->redirect)
203 dst->ops->redirect(dst, skb);
204}
205
198/* 206/*
199 * This routine is called by the ICMP module when it gets some sort of error 207 * This routine is called by the ICMP module when it gets some sort of error
200 * condition. If err < 0 then the socket should be closed and the error 208 * condition. If err < 0 then the socket should be closed and the error
@@ -259,6 +267,9 @@ static void dccp_v4_err(struct sk_buff *skb, u32 info)
259 } 267 }
260 268
261 switch (type) { 269 switch (type) {
270 case ICMP_REDIRECT:
271 dccp_do_redirect(skb, sk);
272 goto out;
262 case ICMP_SOURCE_QUENCH: 273 case ICMP_SOURCE_QUENCH:
263 /* Just silently ignore these. */ 274 /* Just silently ignore these. */
264 goto out; 275 goto out;
diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c
index 916d5ecaf6c6..a0d8392491c3 100644
--- a/net/ipv4/ah4.c
+++ b/net/ipv4/ah4.c
@@ -398,17 +398,25 @@ static void ah4_err(struct sk_buff *skb, u32 info)
398 struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+(iph->ihl<<2)); 398 struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+(iph->ihl<<2));
399 struct xfrm_state *x; 399 struct xfrm_state *x;
400 400
401 if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH || 401 switch (icmp_hdr(skb)->type) {
402 icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) 402 case ICMP_DEST_UNREACH:
403 if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
404 return;
405 case ICMP_REDIRECT:
406 break;
407 default:
403 return; 408 return;
409 }
404 410
405 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, 411 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
406 ah->spi, IPPROTO_AH, AF_INET); 412 ah->spi, IPPROTO_AH, AF_INET);
407 if (!x) 413 if (!x)
408 return; 414 return;
409 pr_debug("pmtu discovery on SA AH/%08x/%08x\n", 415
410 ntohl(ah->spi), ntohl(iph->daddr)); 416 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
411 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0); 417 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_AH, 0);
418 else
419 ipv4_redirect(skb, net, 0, 0, IPPROTO_AH, 0);
412 xfrm_state_put(x); 420 xfrm_state_put(x);
413} 421}
414 422
diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c
index 7b95b49a36ce..b61e9deb7c7e 100644
--- a/net/ipv4/esp4.c
+++ b/net/ipv4/esp4.c
@@ -484,17 +484,25 @@ static void esp4_err(struct sk_buff *skb, u32 info)
484 struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); 484 struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2));
485 struct xfrm_state *x; 485 struct xfrm_state *x;
486 486
487 if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH || 487 switch (icmp_hdr(skb)->type) {
488 icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) 488 case ICMP_DEST_UNREACH:
489 if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
490 return;
491 case ICMP_REDIRECT:
492 break;
493 default:
489 return; 494 return;
495 }
490 496
491 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, 497 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
492 esph->spi, IPPROTO_ESP, AF_INET); 498 esph->spi, IPPROTO_ESP, AF_INET);
493 if (!x) 499 if (!x)
494 return; 500 return;
495 NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n", 501
496 ntohl(esph->spi), ntohl(iph->daddr)); 502 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
497 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0); 503 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_ESP, 0);
504 else
505 ipv4_redirect(skb, net, 0, 0, IPPROTO_ESP, 0);
498 xfrm_state_put(x); 506 xfrm_state_put(x);
499} 507}
500 508
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 594cec35ac4d..0c3123566d76 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -528,6 +528,9 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
528 if (code != ICMP_EXC_TTL) 528 if (code != ICMP_EXC_TTL)
529 return; 529 return;
530 break; 530 break;
531
532 case ICMP_REDIRECT:
533 break;
531 } 534 }
532 535
533 rcu_read_lock(); 536 rcu_read_lock();
@@ -543,7 +546,11 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
543 t->parms.link, 0, IPPROTO_GRE, 0); 546 t->parms.link, 0, IPPROTO_GRE, 0);
544 goto out; 547 goto out;
545 } 548 }
546 549 if (type == ICMP_REDIRECT) {
550 ipv4_redirect(skb, dev_net(skb->dev), t->parms.link, 0,
551 IPPROTO_GRE, 0);
552 goto out;
553 }
547 if (t->parms.iph.daddr == 0 || 554 if (t->parms.iph.daddr == 0 ||
548 ipv4_is_multicast(t->parms.iph.daddr)) 555 ipv4_is_multicast(t->parms.iph.daddr))
549 goto out; 556 goto out;
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index b91375482d84..d3ab47e19a89 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -31,18 +31,26 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info)
31 struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2)); 31 struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
32 struct xfrm_state *x; 32 struct xfrm_state *x;
33 33
34 if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH || 34 switch (icmp_hdr(skb)->type) {
35 icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) 35 case ICMP_DEST_UNREACH:
36 if (icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
37 return;
38 case ICMP_REDIRECT:
39 break;
40 default:
36 return; 41 return;
42 }
37 43
38 spi = htonl(ntohs(ipch->cpi)); 44 spi = htonl(ntohs(ipch->cpi));
39 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, 45 x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr,
40 spi, IPPROTO_COMP, AF_INET); 46 spi, IPPROTO_COMP, AF_INET);
41 if (!x) 47 if (!x)
42 return; 48 return;
43 NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n", 49
44 spi, &iph->daddr); 50 if (icmp_hdr(skb)->type == ICMP_DEST_UNREACH)
45 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0); 51 ipv4_update_pmtu(skb, net, info, 0, 0, IPPROTO_COMP, 0);
52 else
53 ipv4_redirect(skb, net, 0, 0, IPPROTO_COMP, 0);
46 xfrm_state_put(x); 54 xfrm_state_put(x);
47} 55}
48 56
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index 715338a1b205..c2d0e6d8baaf 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -360,6 +360,8 @@ static int ipip_err(struct sk_buff *skb, u32 info)
360 if (code != ICMP_EXC_TTL) 360 if (code != ICMP_EXC_TTL)
361 return 0; 361 return 0;
362 break; 362 break;
363 case ICMP_REDIRECT:
364 break;
363 } 365 }
364 366
365 err = -ENOENT; 367 err = -ENOENT;
@@ -376,6 +378,13 @@ static int ipip_err(struct sk_buff *skb, u32 info)
376 goto out; 378 goto out;
377 } 379 }
378 380
381 if (type == ICMP_REDIRECT) {
382 ipv4_redirect(skb, dev_net(skb->dev), t->dev->ifindex, 0,
383 IPPROTO_IPIP, 0);
384 err = 0;
385 goto out;
386 }
387
379 if (t->parms.iph.daddr == 0) 388 if (t->parms.iph.daddr == 0)
380 goto out; 389 goto out;
381 390
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index 340fcf29a966..6232d476f37e 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -387,6 +387,7 @@ void ping_err(struct sk_buff *skb, u32 info)
387 break; 387 break;
388 case ICMP_REDIRECT: 388 case ICMP_REDIRECT:
389 /* See ICMP_SOURCE_QUENCH */ 389 /* See ICMP_SOURCE_QUENCH */
390 ipv4_sk_redirect(skb, sk);
390 err = EREMOTEIO; 391 err = EREMOTEIO;
391 break; 392 break;
392 } 393 }
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 659ddfb10947..ff0f071969ea 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -218,6 +218,8 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info)
218 218
219 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) 219 if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED)
220 ipv4_sk_update_pmtu(skb, sk, info); 220 ipv4_sk_update_pmtu(skb, sk, info);
221 else if (type == ICMP_REDIRECT)
222 ipv4_sk_redirect(skb, sk);
221 223
222 /* Report error on raw socket, if: 224 /* Report error on raw socket, if:
223 1. User requested ip_recverr. 225 1. User requested ip_recverr.
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 01545a3fc0f2..087a8488843f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -321,6 +321,14 @@ static void do_pmtu_discovery(struct sock *sk, const struct iphdr *iph, u32 mtu)
321 } /* else let the usual retransmit timer handle it */ 321 } /* else let the usual retransmit timer handle it */
322} 322}
323 323
324static void do_redirect(struct sk_buff *skb, struct sock *sk)
325{
326 struct dst_entry *dst = __sk_dst_check(sk, 0);
327
328 if (dst && dst->ops->redirect)
329 dst->ops->redirect(dst, skb);
330}
331
324/* 332/*
325 * This routine is called by the ICMP module when it gets some 333 * This routine is called by the ICMP module when it gets some
326 * sort of error condition. If err < 0 then the socket should 334 * sort of error condition. If err < 0 then the socket should
@@ -394,6 +402,9 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
394 } 402 }
395 403
396 switch (type) { 404 switch (type) {
405 case ICMP_REDIRECT:
406 do_redirect(icmp_skb, sk);
407 goto out;
397 case ICMP_SOURCE_QUENCH: 408 case ICMP_SOURCE_QUENCH:
398 /* Just silently ignore these. */ 409 /* Just silently ignore these. */
399 goto out; 410 goto out;
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index ee37d47d472e..b4c3582a991f 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -630,6 +630,9 @@ void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable)
630 err = icmp_err_convert[code].errno; 630 err = icmp_err_convert[code].errno;
631 } 631 }
632 break; 632 break;
633 case ICMP_REDIRECT:
634 ipv4_sk_redirect(skb, sk);
635 break;
633 } 636 }
634 637
635 /* 638 /*
diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c
index 87d3fcc302d4..258ebd7b268b 100644
--- a/net/ipv4/xfrm4_policy.c
+++ b/net/ipv4/xfrm4_policy.c
@@ -202,6 +202,15 @@ static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu)
202 path->ops->update_pmtu(path, mtu); 202 path->ops->update_pmtu(path, mtu);
203} 203}
204 204
205static void xfrm4_redirect(struct dst_entry *dst, struct sk_buff *skb)
206{
207 struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
208 struct dst_entry *path = xdst->route;
209
210 if (path->ops->redirect)
211 path->ops->redirect(path, skb);
212}
213
205static void xfrm4_dst_destroy(struct dst_entry *dst) 214static void xfrm4_dst_destroy(struct dst_entry *dst)
206{ 215{
207 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 216 struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
@@ -225,6 +234,7 @@ static struct dst_ops xfrm4_dst_ops = {
225 .protocol = cpu_to_be16(ETH_P_IP), 234 .protocol = cpu_to_be16(ETH_P_IP),
226 .gc = xfrm4_garbage_collect, 235 .gc = xfrm4_garbage_collect,
227 .update_pmtu = xfrm4_update_pmtu, 236 .update_pmtu = xfrm4_update_pmtu,
237 .redirect = xfrm4_redirect,
228 .cow_metrics = dst_cow_metrics_generic, 238 .cow_metrics = dst_cow_metrics_generic,
229 .destroy = xfrm4_dst_destroy, 239 .destroy = xfrm4_dst_destroy,
230 .ifdown = xfrm4_dst_ifdown, 240 .ifdown = xfrm4_dst_ifdown,
diff --git a/net/sctp/input.c b/net/sctp/input.c
index 80564fe03024..9fb4247f9a99 100644
--- a/net/sctp/input.c
+++ b/net/sctp/input.c
@@ -423,6 +423,18 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
423 sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD); 423 sctp_retransmit(&asoc->outqueue, t, SCTP_RTXR_PMTUD);
424} 424}
425 425
426static void sctp_icmp_redirect(struct sock *sk, struct sctp_transport *t,
427 struct sk_buff *skb)
428{
429 struct dst_entry *dst;
430
431 if (!t)
432 return;
433 dst = sctp_transport_dst_check(t);
434 if (dst && dst->ops->redirect)
435 dst->ops->redirect(dst, skb);
436}
437
426/* 438/*
427 * SCTP Implementer's Guide, 2.37 ICMP handling procedures 439 * SCTP Implementer's Guide, 2.37 ICMP handling procedures
428 * 440 *
@@ -628,6 +640,10 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
628 640
629 err = EHOSTUNREACH; 641 err = EHOSTUNREACH;
630 break; 642 break;
643 case ICMP_REDIRECT:
644 sctp_icmp_redirect(sk, transport, skb);
645 err = 0;
646 break;
631 default: 647 default:
632 goto out_unlock; 648 goto out_unlock;
633 } 649 }