diff options
author | David S. Miller <davem@davemloft.net> | 2012-07-12 03:25:15 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-12 03:25:15 -0400 |
commit | ec18d9a2691d69cd14b48f9b919fddcef28b7f5c (patch) | |
tree | 4d10135edfe25d4ff56e39330b0f7797b2034b8a | |
parent | 3a5ad2ee5e2c5030d8a303d06f9148a2f893a369 (diff) |
ipv6: Add redirect support to all protocol icmp error handlers.
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/net/sctp/sctp.h | 2 | ||||
-rw-r--r-- | net/dccp/ipv6.c | 7 | ||||
-rw-r--r-- | net/ipv6/ah6.c | 10 | ||||
-rw-r--r-- | net/ipv6/esp6.c | 11 | ||||
-rw-r--r-- | net/ipv6/ip6_tunnel.c | 7 | ||||
-rw-r--r-- | net/ipv6/ipcomp6.c | 11 | ||||
-rw-r--r-- | net/ipv6/raw.c | 2 | ||||
-rw-r--r-- | net/ipv6/sit.c | 8 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 7 | ||||
-rw-r--r-- | net/ipv6/udp.c | 2 | ||||
-rw-r--r-- | net/ipv6/xfrm6_policy.c | 9 | ||||
-rw-r--r-- | net/sctp/input.c | 4 | ||||
-rw-r--r-- | net/sctp/ipv6.c | 3 |
13 files changed, 69 insertions, 14 deletions
diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index a2ef81466b00..1f2735dba753 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h | |||
@@ -162,6 +162,8 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *, | |||
162 | void sctp_err_finish(struct sock *, struct sctp_association *); | 162 | void sctp_err_finish(struct sock *, struct sctp_association *); |
163 | void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, | 163 | void sctp_icmp_frag_needed(struct sock *, struct sctp_association *, |
164 | struct sctp_transport *t, __u32 pmtu); | 164 | struct sctp_transport *t, __u32 pmtu); |
165 | void sctp_icmp_redirect(struct sock *, struct sctp_transport *, | ||
166 | struct sk_buff *); | ||
165 | void sctp_icmp_proto_unreachable(struct sock *sk, | 167 | void sctp_icmp_proto_unreachable(struct sock *sk, |
166 | struct sctp_association *asoc, | 168 | struct sctp_association *asoc, |
167 | struct sctp_transport *t); | 169 | struct sctp_transport *t); |
diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 02162cfa5048..b4d7d28ce6d2 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c | |||
@@ -130,6 +130,13 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
130 | 130 | ||
131 | np = inet6_sk(sk); | 131 | np = inet6_sk(sk); |
132 | 132 | ||
133 | if (type == NDISC_REDIRECT) { | ||
134 | struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie); | ||
135 | |||
136 | if (dst && dst->ops->redirect) | ||
137 | dst->ops->redirect(dst, skb); | ||
138 | } | ||
139 | |||
133 | if (type == ICMPV6_PKT_TOOBIG) { | 140 | if (type == ICMPV6_PKT_TOOBIG) { |
134 | struct dst_entry *dst = NULL; | 141 | struct dst_entry *dst = NULL; |
135 | 142 | ||
diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 49d4d26bda88..7e6139508ee7 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c | |||
@@ -613,16 +613,18 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
613 | struct xfrm_state *x; | 613 | struct xfrm_state *x; |
614 | 614 | ||
615 | if (type != ICMPV6_DEST_UNREACH && | 615 | if (type != ICMPV6_DEST_UNREACH && |
616 | type != ICMPV6_PKT_TOOBIG) | 616 | type != ICMPV6_PKT_TOOBIG && |
617 | type != NDISC_REDIRECT) | ||
617 | return; | 618 | return; |
618 | 619 | ||
619 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); | 620 | x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); |
620 | if (!x) | 621 | if (!x) |
621 | return; | 622 | return; |
622 | 623 | ||
623 | NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/%pI6\n", | 624 | if (type == NDISC_REDIRECT) |
624 | ntohl(ah->spi), &iph->daddr); | 625 | ip6_redirect(skb, net, 0, 0); |
625 | ip6_update_pmtu(skb, net, info, 0, 0); | 626 | else |
627 | ip6_update_pmtu(skb, net, info, 0, 0); | ||
626 | xfrm_state_put(x); | 628 | xfrm_state_put(x); |
627 | } | 629 | } |
628 | 630 | ||
diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index 89a615ba84f8..6dc7fd353ef5 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c | |||
@@ -434,16 +434,19 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
434 | struct xfrm_state *x; | 434 | struct xfrm_state *x; |
435 | 435 | ||
436 | if (type != ICMPV6_DEST_UNREACH && | 436 | if (type != ICMPV6_DEST_UNREACH && |
437 | type != ICMPV6_PKT_TOOBIG) | 437 | type != ICMPV6_PKT_TOOBIG && |
438 | type != NDISC_REDIRECT) | ||
438 | return; | 439 | return; |
439 | 440 | ||
440 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, | 441 | x = xfrm_state_lookup(net, skb->mark, (const xfrm_address_t *)&iph->daddr, |
441 | esph->spi, IPPROTO_ESP, AF_INET6); | 442 | esph->spi, IPPROTO_ESP, AF_INET6); |
442 | if (!x) | 443 | if (!x) |
443 | return; | 444 | return; |
444 | pr_debug("pmtu discovery on SA ESP/%08x/%pI6\n", | 445 | |
445 | ntohl(esph->spi), &iph->daddr); | 446 | if (type == NDISC_REDIRECT) |
446 | ip6_update_pmtu(skb, net, info, 0, 0); | 447 | ip6_redirect(skb, net, 0, 0); |
448 | else | ||
449 | ip6_update_pmtu(skb, net, info, 0, 0); | ||
447 | xfrm_state_put(x); | 450 | xfrm_state_put(x); |
448 | } | 451 | } |
449 | 452 | ||
diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 6af3fcfdcbbd..0b5b60ec6f4a 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c | |||
@@ -550,6 +550,9 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
550 | rel_type = ICMP_DEST_UNREACH; | 550 | rel_type = ICMP_DEST_UNREACH; |
551 | rel_code = ICMP_FRAG_NEEDED; | 551 | rel_code = ICMP_FRAG_NEEDED; |
552 | break; | 552 | break; |
553 | case NDISC_REDIRECT: | ||
554 | rel_type = ICMP_REDIRECT; | ||
555 | rel_code = ICMP_REDIR_HOST; | ||
553 | default: | 556 | default: |
554 | return 0; | 557 | return 0; |
555 | } | 558 | } |
@@ -608,6 +611,10 @@ ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
608 | 611 | ||
609 | skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), rel_info); | 612 | skb_dst(skb2)->ops->update_pmtu(skb_dst(skb2), rel_info); |
610 | } | 613 | } |
614 | if (rel_type == ICMP_REDIRECT) { | ||
615 | if (skb_dst(skb2)->ops->redirect) | ||
616 | skb_dst(skb2)->ops->redirect(skb_dst(skb2), skb2); | ||
617 | } | ||
611 | 618 | ||
612 | icmp_send(skb2, rel_type, rel_code, htonl(rel_info)); | 619 | icmp_send(skb2, rel_type, rel_code, htonl(rel_info)); |
613 | 620 | ||
diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 92832385a8ef..7af5aee75d98 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c | |||
@@ -64,7 +64,9 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
64 | (struct ip_comp_hdr *)(skb->data + offset); | 64 | (struct ip_comp_hdr *)(skb->data + offset); |
65 | struct xfrm_state *x; | 65 | struct xfrm_state *x; |
66 | 66 | ||
67 | if (type != ICMPV6_DEST_UNREACH && type != ICMPV6_PKT_TOOBIG) | 67 | if (type != ICMPV6_DEST_UNREACH && |
68 | type != ICMPV6_PKT_TOOBIG && | ||
69 | type != NDISC_REDIRECT) | ||
68 | return; | 70 | return; |
69 | 71 | ||
70 | spi = htonl(ntohs(ipcomph->cpi)); | 72 | spi = htonl(ntohs(ipcomph->cpi)); |
@@ -73,9 +75,10 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
73 | if (!x) | 75 | if (!x) |
74 | return; | 76 | return; |
75 | 77 | ||
76 | pr_debug("pmtu discovery on SA IPCOMP/%08x/%pI6\n", | 78 | if (type == NDISC_REDIRECT) |
77 | spi, &iph->daddr); | 79 | ip6_redirect(skb, net, 0, 0); |
78 | ip6_update_pmtu(skb, net, info, 0, 0); | 80 | else |
81 | ip6_update_pmtu(skb, net, info, 0, 0); | ||
79 | xfrm_state_put(x); | 82 | xfrm_state_put(x); |
80 | } | 83 | } |
81 | 84 | ||
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index b5c1dcb27737..ef0579d5bca6 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c | |||
@@ -332,6 +332,8 @@ static void rawv6_err(struct sock *sk, struct sk_buff *skb, | |||
332 | ip6_sk_update_pmtu(skb, sk, info); | 332 | ip6_sk_update_pmtu(skb, sk, info); |
333 | harderr = (np->pmtudisc == IPV6_PMTUDISC_DO); | 333 | harderr = (np->pmtudisc == IPV6_PMTUDISC_DO); |
334 | } | 334 | } |
335 | if (type == NDISC_REDIRECT) | ||
336 | ip6_sk_redirect(skb, sk); | ||
335 | if (np->recverr) { | 337 | if (np->recverr) { |
336 | u8 *payload = skb->data; | 338 | u8 *payload = skb->data; |
337 | if (!inet->hdrincl) | 339 | if (!inet->hdrincl) |
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 49aea94c9be3..fbf1622fdeef 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c | |||
@@ -539,6 +539,8 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
539 | if (code != ICMP_EXC_TTL) | 539 | if (code != ICMP_EXC_TTL) |
540 | return 0; | 540 | return 0; |
541 | break; | 541 | break; |
542 | case ICMP_REDIRECT: | ||
543 | break; | ||
542 | } | 544 | } |
543 | 545 | ||
544 | err = -ENOENT; | 546 | err = -ENOENT; |
@@ -557,6 +559,12 @@ static int ipip6_err(struct sk_buff *skb, u32 info) | |||
557 | err = 0; | 559 | err = 0; |
558 | goto out; | 560 | goto out; |
559 | } | 561 | } |
562 | if (type == ICMP_REDIRECT) { | ||
563 | ipv4_redirect(skb, dev_net(skb->dev), t->dev->ifindex, 0, | ||
564 | IPPROTO_IPV6, 0); | ||
565 | err = 0; | ||
566 | goto out; | ||
567 | } | ||
560 | 568 | ||
561 | if (t->parms.iph.daddr == 0) | 569 | if (t->parms.iph.daddr == 0) |
562 | goto out; | 570 | goto out; |
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 70458a9cd837..7249e4bb9b8a 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -363,6 +363,13 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
363 | 363 | ||
364 | np = inet6_sk(sk); | 364 | np = inet6_sk(sk); |
365 | 365 | ||
366 | if (type == NDISC_REDIRECT) { | ||
367 | struct dst_entry *dst = __sk_dst_check(sk, np->dst_cookie); | ||
368 | |||
369 | if (dst && dst->ops->redirect) | ||
370 | dst->ops->redirect(dst,skb); | ||
371 | } | ||
372 | |||
366 | if (type == ICMPV6_PKT_TOOBIG) { | 373 | if (type == ICMPV6_PKT_TOOBIG) { |
367 | struct dst_entry *dst; | 374 | struct dst_entry *dst; |
368 | 375 | ||
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 1ecd10249488..99d0077b56b8 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c | |||
@@ -483,6 +483,8 @@ void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
483 | 483 | ||
484 | if (type == ICMPV6_PKT_TOOBIG) | 484 | if (type == ICMPV6_PKT_TOOBIG) |
485 | ip6_sk_update_pmtu(skb, sk, info); | 485 | ip6_sk_update_pmtu(skb, sk, info); |
486 | if (type == NDISC_REDIRECT) | ||
487 | ip6_sk_redirect(skb, sk); | ||
486 | 488 | ||
487 | np = inet6_sk(sk); | 489 | np = inet6_sk(sk); |
488 | 490 | ||
diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index bb02038b822b..f5a9cb8257b9 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c | |||
@@ -215,6 +215,14 @@ static void xfrm6_update_pmtu(struct dst_entry *dst, u32 mtu) | |||
215 | path->ops->update_pmtu(path, mtu); | 215 | path->ops->update_pmtu(path, mtu); |
216 | } | 216 | } |
217 | 217 | ||
218 | static void xfrm6_redirect(struct dst_entry *dst, struct sk_buff *skb) | ||
219 | { | ||
220 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | ||
221 | struct dst_entry *path = xdst->route; | ||
222 | |||
223 | path->ops->redirect(path, skb); | ||
224 | } | ||
225 | |||
218 | static void xfrm6_dst_destroy(struct dst_entry *dst) | 226 | static void xfrm6_dst_destroy(struct dst_entry *dst) |
219 | { | 227 | { |
220 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; | 228 | struct xfrm_dst *xdst = (struct xfrm_dst *)dst; |
@@ -261,6 +269,7 @@ static struct dst_ops xfrm6_dst_ops = { | |||
261 | .protocol = cpu_to_be16(ETH_P_IPV6), | 269 | .protocol = cpu_to_be16(ETH_P_IPV6), |
262 | .gc = xfrm6_garbage_collect, | 270 | .gc = xfrm6_garbage_collect, |
263 | .update_pmtu = xfrm6_update_pmtu, | 271 | .update_pmtu = xfrm6_update_pmtu, |
272 | .redirect = xfrm6_redirect, | ||
264 | .cow_metrics = dst_cow_metrics_generic, | 273 | .cow_metrics = dst_cow_metrics_generic, |
265 | .destroy = xfrm6_dst_destroy, | 274 | .destroy = xfrm6_dst_destroy, |
266 | .ifdown = xfrm6_dst_ifdown, | 275 | .ifdown = xfrm6_dst_ifdown, |
diff --git a/net/sctp/input.c b/net/sctp/input.c index 9fb4247f9a99..5943b7d77ddb 100644 --- a/net/sctp/input.c +++ b/net/sctp/input.c | |||
@@ -423,8 +423,8 @@ 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 | ||
426 | static void sctp_icmp_redirect(struct sock *sk, struct sctp_transport *t, | 426 | void sctp_icmp_redirect(struct sock *sk, struct sctp_transport *t, |
427 | struct sk_buff *skb) | 427 | struct sk_buff *skb) |
428 | { | 428 | { |
429 | struct dst_entry *dst; | 429 | struct dst_entry *dst; |
430 | 430 | ||
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 91f479121c55..ed7139ea7978 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
@@ -185,6 +185,9 @@ SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, | |||
185 | goto out_unlock; | 185 | goto out_unlock; |
186 | } | 186 | } |
187 | break; | 187 | break; |
188 | case NDISC_REDIRECT: | ||
189 | sctp_icmp_redirect(sk, transport, skb); | ||
190 | break; | ||
188 | default: | 191 | default: |
189 | break; | 192 | break; |
190 | } | 193 | } |