Commit 9f8fbf30 authored by James Morris's avatar James Morris

[IPSEC]: pmtu discovery support at local tunnel gateway.

parent 700a4acb
...@@ -47,6 +47,7 @@ struct inet_skb_parm ...@@ -47,6 +47,7 @@ struct inet_skb_parm
#define IPSKB_MASQUERADED 1 #define IPSKB_MASQUERADED 1
#define IPSKB_TRANSLATED 2 #define IPSKB_TRANSLATED 2
#define IPSKB_FORWARDED 4 #define IPSKB_FORWARDED 4
#define IPSKB_XFRM_TUNNEL_SIZE 8
}; };
struct ipcm_cookie struct ipcm_cookie
......
...@@ -760,6 +760,7 @@ extern int xfrm4_rcv(struct sk_buff *skb); ...@@ -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_rcv_encap(struct sk_buff *skb, __u16 encap_type);
extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler);
extern int xfrm4_tunnel_deregister(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_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 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); extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
......
...@@ -74,6 +74,9 @@ static int ah_output(struct sk_buff *skb) ...@@ -74,6 +74,9 @@ static int ah_output(struct sk_buff *skb)
spin_lock_bh(&x->lock); spin_lock_bh(&x->lock);
if ((err = xfrm_state_check_expire(x)) != 0) if ((err = xfrm_state_check_expire(x)) != 0)
goto error; 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) if ((err = xfrm_state_check_space(x, skb)) != 0)
goto error; goto error;
......
...@@ -49,6 +49,9 @@ int esp_output(struct sk_buff *skb) ...@@ -49,6 +49,9 @@ int esp_output(struct sk_buff *skb)
spin_lock_bh(&x->lock); spin_lock_bh(&x->lock);
if ((err = xfrm_state_check_expire(x)) != 0) if ((err = xfrm_state_check_expire(x)) != 0)
goto error; 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) if ((err = xfrm_state_check_space(x, skb)) != 0)
goto error; goto error;
......
...@@ -176,6 +176,9 @@ static int ipcomp_output(struct sk_buff *skb) ...@@ -176,6 +176,9 @@ static int ipcomp_output(struct sk_buff *skb)
if ((err = xfrm_state_check_expire(x)) != 0) if ((err = xfrm_state_check_expire(x)) != 0)
goto error; 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) if ((err = xfrm_state_check_space(x, skb)) != 0)
goto error; goto error;
......
...@@ -9,12 +9,39 @@ ...@@ -9,12 +9,39 @@
#include <net/icmp.h> #include <net/icmp.h>
#include <net/inet_ecn.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) static int ipip_output(struct sk_buff *skb)
{ {
struct dst_entry *dst = skb->dst; struct dst_entry *dst = skb->dst;
struct xfrm_state *x = dst->xfrm; struct xfrm_state *x = dst->xfrm;
struct iphdr *iph, *top_iph; 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; iph = skb->nh.iph;
...@@ -46,9 +73,14 @@ static int ipip_output(struct sk_buff *skb) ...@@ -46,9 +73,14 @@ static int ipip_output(struct sk_buff *skb)
if ((skb->dst = dst_pop(dst)) == NULL) { if ((skb->dst = dst_pop(dst)) == NULL) {
kfree_skb(skb); kfree_skb(skb);
return -EHOSTUNREACH; err = -EHOSTUNREACH;
goto error_nolock;
} }
return NET_XMIT_BYPASS; 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) static inline void ipip_ecn_decapsulate(struct iphdr *outer_iph, struct sk_buff *skb)
......
...@@ -320,6 +320,7 @@ EXPORT_SYMBOL(xfrm_parse_spi); ...@@ -320,6 +320,7 @@ EXPORT_SYMBOL(xfrm_parse_spi);
EXPORT_SYMBOL(xfrm4_rcv); EXPORT_SYMBOL(xfrm4_rcv);
EXPORT_SYMBOL(xfrm4_tunnel_register); EXPORT_SYMBOL(xfrm4_tunnel_register);
EXPORT_SYMBOL(xfrm4_tunnel_deregister); EXPORT_SYMBOL(xfrm4_tunnel_deregister);
EXPORT_SYMBOL(xfrm4_tunnel_check_size);
EXPORT_SYMBOL(xfrm_register_type); EXPORT_SYMBOL(xfrm_register_type);
EXPORT_SYMBOL(xfrm_unregister_type); EXPORT_SYMBOL(xfrm_unregister_type);
EXPORT_SYMBOL(xfrm_get_type); EXPORT_SYMBOL(xfrm_get_type);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment