]> git.neil.brown.name Git - history.git/commitdiff
[IPSEC]: pmtu discovery support at local tunnel gateway.
authorJames Morris <jmorris@intercode.com.au>
Wed, 30 Apr 2003 20:25:51 +0000 (13:25 -0700)
committerJames Morris <jmorris@intercode.com.au>
Wed, 30 Apr 2003 20:25:51 +0000 (13:25 -0700)
include/net/ip.h
include/net/xfrm.h
net/ipv4/ah.c
net/ipv4/esp.c
net/ipv4/ipcomp.c
net/ipv4/xfrm4_tunnel.c
net/netsyms.c

index da0dab10f4f00030f58c4955e6a6369c60a3ea28..25e95ec9b4fb4494f3d1b97ddc0c2623e68b0629 100644 (file)
@@ -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
index b3a67d100b4d0950194c462a055d77be07366656..f478323f39b0dbc8bb0a9154caca8ac36ba361c4 100644 (file)
@@ -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);
index 02f08aa24437662fbd3bce87324c35ec1d4f9af7..b8388d112bbb8bb8501867b9f14b6ec8ccb7741b 100644 (file)
@@ -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;
 
index db29b32b118e6a869ae2846bbc9d75eaec49b2b5..e7736ecac34bc0f1328472d21cfab225b6cd682a 100644 (file)
@@ -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;
 
index 9b59d2bc13f82c82037b1eb2f17a29b72b461a03..fd96657645ab860efc435b61e75b15a40c0c7dc4 100644 (file)
@@ -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;
 
index 94823a21c09a631700aa5390f480926ed01f929b..d6bfc1e061bd77666c1a5edefb80526dce2f2ca9 100644 (file)
@@ -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)
index 881e6ca329026c07e57ca5e3008c55e2e541b953..7859d0f96c51b2adfc1f9fd2b83779bb885f6d8e 100644 (file)
@@ -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);