diff options
-rw-r--r-- | include/net/ip.h | 2 | ||||
-rw-r--r-- | net/ipv4/cipso_ipv4.c | 17 | ||||
-rw-r--r-- | net/ipv4/ip_options.c | 22 |
3 files changed, 34 insertions, 7 deletions
diff --git a/include/net/ip.h b/include/net/ip.h index 8866bfce6121..f0e8d064e249 100644 --- a/include/net/ip.h +++ b/include/net/ip.h | |||
@@ -667,6 +667,8 @@ static inline int ip_options_echo(struct net *net, struct ip_options *dopt, | |||
667 | } | 667 | } |
668 | 668 | ||
669 | void ip_options_fragment(struct sk_buff *skb); | 669 | void ip_options_fragment(struct sk_buff *skb); |
670 | int __ip_options_compile(struct net *net, struct ip_options *opt, | ||
671 | struct sk_buff *skb, __be32 *info); | ||
670 | int ip_options_compile(struct net *net, struct ip_options *opt, | 672 | int ip_options_compile(struct net *net, struct ip_options *opt, |
671 | struct sk_buff *skb); | 673 | struct sk_buff *skb); |
672 | int ip_options_get(struct net *net, struct ip_options_rcu **optp, | 674 | int ip_options_get(struct net *net, struct ip_options_rcu **optp, |
diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 777fa3b7fb13..eff86a71c1b0 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c | |||
@@ -1735,13 +1735,26 @@ validate_return: | |||
1735 | */ | 1735 | */ |
1736 | void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) | 1736 | void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) |
1737 | { | 1737 | { |
1738 | unsigned char optbuf[sizeof(struct ip_options) + 40]; | ||
1739 | struct ip_options *opt = (struct ip_options *)optbuf; | ||
1740 | |||
1738 | if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES) | 1741 | if (ip_hdr(skb)->protocol == IPPROTO_ICMP || error != -EACCES) |
1739 | return; | 1742 | return; |
1740 | 1743 | ||
1744 | /* | ||
1745 | * We might be called above the IP layer, | ||
1746 | * so we can not use icmp_send and IPCB here. | ||
1747 | */ | ||
1748 | |||
1749 | memset(opt, 0, sizeof(struct ip_options)); | ||
1750 | opt->optlen = ip_hdr(skb)->ihl*4 - sizeof(struct iphdr); | ||
1751 | if (__ip_options_compile(dev_net(skb->dev), opt, skb, NULL)) | ||
1752 | return; | ||
1753 | |||
1741 | if (gateway) | 1754 | if (gateway) |
1742 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0); | 1755 | __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_ANO, 0, opt); |
1743 | else | 1756 | else |
1744 | icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0); | 1757 | __icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_ANO, 0, opt); |
1745 | } | 1758 | } |
1746 | 1759 | ||
1747 | /** | 1760 | /** |
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index ed194d46c00e..32a35043c9f5 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c | |||
@@ -251,8 +251,9 @@ static void spec_dst_fill(__be32 *spec_dst, struct sk_buff *skb) | |||
251 | * If opt == NULL, then skb->data should point to IP header. | 251 | * If opt == NULL, then skb->data should point to IP header. |
252 | */ | 252 | */ |
253 | 253 | ||
254 | int ip_options_compile(struct net *net, | 254 | int __ip_options_compile(struct net *net, |
255 | struct ip_options *opt, struct sk_buff *skb) | 255 | struct ip_options *opt, struct sk_buff *skb, |
256 | __be32 *info) | ||
256 | { | 257 | { |
257 | __be32 spec_dst = htonl(INADDR_ANY); | 258 | __be32 spec_dst = htonl(INADDR_ANY); |
258 | unsigned char *pp_ptr = NULL; | 259 | unsigned char *pp_ptr = NULL; |
@@ -468,11 +469,22 @@ eol: | |||
468 | return 0; | 469 | return 0; |
469 | 470 | ||
470 | error: | 471 | error: |
471 | if (skb) { | 472 | if (info) |
472 | icmp_send(skb, ICMP_PARAMETERPROB, 0, htonl((pp_ptr-iph)<<24)); | 473 | *info = htonl((pp_ptr-iph)<<24); |
473 | } | ||
474 | return -EINVAL; | 474 | return -EINVAL; |
475 | } | 475 | } |
476 | |||
477 | int ip_options_compile(struct net *net, | ||
478 | struct ip_options *opt, struct sk_buff *skb) | ||
479 | { | ||
480 | int ret; | ||
481 | __be32 info; | ||
482 | |||
483 | ret = __ip_options_compile(net, opt, skb, &info); | ||
484 | if (ret != 0 && skb) | ||
485 | icmp_send(skb, ICMP_PARAMETERPROB, 0, info); | ||
486 | return ret; | ||
487 | } | ||
476 | EXPORT_SYMBOL(ip_options_compile); | 488 | EXPORT_SYMBOL(ip_options_compile); |
477 | 489 | ||
478 | /* | 490 | /* |