summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/ip.h1
-rw-r--r--include/net/xfrm.h1
-rw-r--r--net/ipv4/ah.c3
-rw-r--r--net/ipv4/esp.c3
-rw-r--r--net/ipv4/ipcomp.c3
-rw-r--r--net/ipv4/xfrm4_tunnel.c36
-rw-r--r--net/netsyms.c1
7 files changed, 46 insertions, 2 deletions
diff --git a/include/net/ip.h b/include/net/ip.h
index da0dab10f4f0..25e95ec9b4fb 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -47,6 +47,7 @@ struct inet_skb_parm
#define IPSKB_MASQUERADED 1
#define IPSKB_TRANSLATED 2
#define IPSKB_FORWARDED 4
+#define IPSKB_XFRM_TUNNEL_SIZE 8
};
struct ipcm_cookie
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index b3a67d100b4d..f478323f39b0 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -760,6 +760,7 @@ extern int xfrm4_rcv(struct sk_buff *skb);
extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler);
+extern int xfrm4_tunnel_check_size(struct sk_buff *skb);
extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp);
extern int xfrm6_clear_mutable_options(struct sk_buff *skb, u16 *nh_offset, int dir);
extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
diff --git a/net/ipv4/ah.c b/net/ipv4/ah.c
index 02f08aa24437..b8388d112bbb 100644
--- a/net/ipv4/ah.c
+++ b/net/ipv4/ah.c
@@ -74,6 +74,9 @@ static int ah_output(struct sk_buff *skb)
spin_lock_bh(&x->lock);
if ((err = xfrm_state_check_expire(x)) != 0)
goto error;
+ if (x->props.mode)
+ if ((err = xfrm4_tunnel_check_size(skb)) != 0)
+ goto error;
if ((err = xfrm_state_check_space(x, skb)) != 0)
goto error;
diff --git a/net/ipv4/esp.c b/net/ipv4/esp.c
index db29b32b118e..e7736ecac34b 100644
--- a/net/ipv4/esp.c
+++ b/net/ipv4/esp.c
@@ -49,6 +49,9 @@ int esp_output(struct sk_buff *skb)
spin_lock_bh(&x->lock);
if ((err = xfrm_state_check_expire(x)) != 0)
goto error;
+ if (x->props.mode)
+ if ((err = xfrm4_tunnel_check_size(skb)) != 0)
+ goto error;
if ((err = xfrm_state_check_space(x, skb)) != 0)
goto error;
diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
index 9b59d2bc13f8..fd96657645ab 100644
--- a/net/ipv4/ipcomp.c
+++ b/net/ipv4/ipcomp.c
@@ -176,6 +176,9 @@ static int ipcomp_output(struct sk_buff *skb)
if ((err = xfrm_state_check_expire(x)) != 0)
goto error;
+ if (x->props.mode)
+ if ((err = xfrm4_tunnel_check_size(skb)) != 0)
+ goto error;
if ((err = xfrm_state_check_space(x, skb)) != 0)
goto error;
diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
index 94823a21c09a..d6bfc1e061bd 100644
--- a/net/ipv4/xfrm4_tunnel.c
+++ b/net/ipv4/xfrm4_tunnel.c
@@ -9,13 +9,40 @@
#include <net/icmp.h>
#include <net/inet_ecn.h>
+int xfrm4_tunnel_check_size(struct sk_buff *skb)
+{
+ int mtu, ret = 0;
+ struct dst_entry *dst;
+ struct iphdr *iph = skb->nh.iph;
+
+ if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
+ goto out;
+
+ IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;
+
+ if (!(iph->frag_off & htons(IP_DF)))
+ goto out;
+
+ dst = skb->dst;
+ mtu = dst_pmtu(dst) - dst->header_len - dst->trailer_len;
+ if (skb->len > mtu) {
+ icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
+ ret = -EMSGSIZE;
+ }
+out:
+ return ret;
+}
+
static int ipip_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
struct xfrm_state *x = dst->xfrm;
struct iphdr *iph, *top_iph;
- int tos;
+ int tos, err;
+ if ((err = xfrm4_tunnel_check_size(skb)) != 0)
+ goto error_nolock;
+
iph = skb->nh.iph;
spin_lock_bh(&x->lock);
@@ -46,9 +73,14 @@ static int ipip_output(struct sk_buff *skb)
if ((skb->dst = dst_pop(dst)) == NULL) {
kfree_skb(skb);
- return -EHOSTUNREACH;
+ err = -EHOSTUNREACH;
+ goto error_nolock;
}
return NET_XMIT_BYPASS;
+
+error_nolock:
+ kfree_skb(skb);
+ return err;
}
static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb)
diff --git a/net/netsyms.c b/net/netsyms.c
index 881e6ca32902..7859d0f96c51 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -320,6 +320,7 @@ EXPORT_SYMBOL(xfrm_parse_spi);
EXPORT_SYMBOL(xfrm4_rcv);
EXPORT_SYMBOL(xfrm4_tunnel_register);
EXPORT_SYMBOL(xfrm4_tunnel_deregister);
+EXPORT_SYMBOL(xfrm4_tunnel_check_size);
EXPORT_SYMBOL(xfrm_register_type);
EXPORT_SYMBOL(xfrm_unregister_type);
EXPORT_SYMBOL(xfrm_get_type);