diff options
Diffstat (limited to 'net/ipv4/xfrm4_output.c')
| -rw-r--r-- | net/ipv4/xfrm4_output.c | 53 | 
1 files changed, 36 insertions, 17 deletions
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c index 571aa96a175..d5f6bd9a210 100644 --- a/net/ipv4/xfrm4_output.c +++ b/net/ipv4/xfrm4_output.c @@ -21,18 +21,20 @@  static int xfrm4_tunnel_check_size(struct sk_buff *skb)  {  	int mtu, ret = 0; -	struct dst_entry *dst;  	if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)  		goto out; -	if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->local_df) +	if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df)  		goto out; -	dst = skb_dst(skb); -	mtu = dst_mtu(dst); +	mtu = dst_mtu(skb_dst(skb));  	if (skb->len > mtu) { -		icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); +		if (skb->sk) +			xfrm_local_error(skb, mtu); +		else +			icmp_send(skb, ICMP_DEST_UNREACH, +				  ICMP_FRAG_NEEDED, htonl(mtu));  		ret = -EMSGSIZE;  	}  out: @@ -60,33 +62,50 @@ int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)  	if (err)  		return err; -	memset(IPCB(skb), 0, sizeof(*IPCB(skb))); -	IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE | IPSKB_XFRM_TRANSFORMED; - -	skb->protocol = htons(ETH_P_IP); +	IPCB(skb)->flags |= IPSKB_XFRM_TUNNEL_SIZE;  	return x->outer_mode->output2(x, skb);  }  EXPORT_SYMBOL(xfrm4_prepare_output); -static int xfrm4_output_finish(struct sk_buff *skb) +int xfrm4_output_finish(struct sk_buff *skb)  { +	memset(IPCB(skb), 0, sizeof(*IPCB(skb))); +	skb->protocol = htons(ETH_P_IP); +  #ifdef CONFIG_NETFILTER -	if (!skb_dst(skb)->xfrm) { +	IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED; +#endif + +	return xfrm_output(skb); +} + +static int __xfrm4_output(struct sk_buff *skb) +{ +	struct xfrm_state *x = skb_dst(skb)->xfrm; + +#ifdef CONFIG_NETFILTER +	if (!x) {  		IPCB(skb)->flags |= IPSKB_REROUTED;  		return dst_output(skb);  	} - -	IPCB(skb)->flags |= IPSKB_XFRM_TRANSFORMED;  #endif -	skb->protocol = htons(ETH_P_IP); -	return xfrm_output(skb); +	return x->outer_mode->afinfo->output_finish(skb);  } -int xfrm4_output(struct sk_buff *skb) +int xfrm4_output(struct sock *sk, struct sk_buff *skb)  {  	return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, -			    NULL, skb_dst(skb)->dev, xfrm4_output_finish, +			    NULL, skb_dst(skb)->dev, __xfrm4_output,  			    !(IPCB(skb)->flags & IPSKB_REROUTED));  } + +void xfrm4_local_error(struct sk_buff *skb, u32 mtu) +{ +	struct iphdr *hdr; + +	hdr = skb->encapsulation ? inner_ip_hdr(skb) : ip_hdr(skb); +	ip_local_error(skb->sk, EMSGSIZE, hdr->daddr, +		       inet_sk(skb->sk)->inet_dport, mtu); +}  | 
