aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/ip.h2
-rw-r--r--net/ipv4/cipso_ipv4.c17
-rw-r--r--net/ipv4/ip_options.c22
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
669void ip_options_fragment(struct sk_buff *skb); 669void ip_options_fragment(struct sk_buff *skb);
670int __ip_options_compile(struct net *net, struct ip_options *opt,
671 struct sk_buff *skb, __be32 *info);
670int ip_options_compile(struct net *net, struct ip_options *opt, 672int ip_options_compile(struct net *net, struct ip_options *opt,
671 struct sk_buff *skb); 673 struct sk_buff *skb);
672int ip_options_get(struct net *net, struct ip_options_rcu **optp, 674int 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 */
1736void cipso_v4_error(struct sk_buff *skb, int error, u32 gateway) 1736void 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
254int ip_options_compile(struct net *net, 254int __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
470error: 471error:
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
477int 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}
476EXPORT_SYMBOL(ip_options_compile); 488EXPORT_SYMBOL(ip_options_compile);
477 489
478/* 490/*