60d5fcfb19
The nhoff field isn't actually necessary in xfrm_input. For tunnel mode transforms we now throw away the output IP header so it makes no sense to fill in the nexthdr field. For transport mode we can now let the function transport_finish do the setting and it knows where the nexthdr field is. The only other thing that needs the nexthdr field to be set is the header extraction code. However, we can simply move the protocol extraction out of the generic header extraction. We want to minimise the amount of info we have to carry around between transforms as this simplifies the resumption process for async crypto. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
92 lines
2.1 KiB
C
92 lines
2.1 KiB
C
/*
|
|
* xfrm4_output.c - Common IPsec encapsulation code for IPv4.
|
|
* Copyright (c) 2004 Herbert Xu <herbert@gondor.apana.org.au>
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version
|
|
* 2 of the License, or (at your option) any later version.
|
|
*/
|
|
|
|
#include <linux/if_ether.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/skbuff.h>
|
|
#include <linux/netfilter_ipv4.h>
|
|
#include <net/dst.h>
|
|
#include <net/ip.h>
|
|
#include <net/xfrm.h>
|
|
#include <net/icmp.h>
|
|
|
|
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)
|
|
goto out;
|
|
|
|
dst = skb->dst;
|
|
mtu = dst_mtu(dst);
|
|
if (skb->len > mtu) {
|
|
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu));
|
|
ret = -EMSGSIZE;
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
int err;
|
|
|
|
err = xfrm4_tunnel_check_size(skb);
|
|
if (err)
|
|
return err;
|
|
|
|
XFRM_MODE_SKB_CB(skb)->protocol = ip_hdr(skb)->protocol;
|
|
|
|
return xfrm4_extract_header(skb);
|
|
}
|
|
|
|
int xfrm4_prepare_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
int err;
|
|
|
|
err = x->inner_mode->afinfo->extract_output(x, 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);
|
|
|
|
return x->outer_mode->output2(x, skb);
|
|
}
|
|
EXPORT_SYMBOL(xfrm4_prepare_output);
|
|
|
|
static int xfrm4_output_finish(struct sk_buff *skb)
|
|
{
|
|
#ifdef CONFIG_NETFILTER
|
|
if (!skb->dst->xfrm) {
|
|
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);
|
|
}
|
|
|
|
int xfrm4_output(struct sk_buff *skb)
|
|
{
|
|
return NF_HOOK_COND(PF_INET, NF_IP_POST_ROUTING, skb, NULL, skb->dst->dev,
|
|
xfrm4_output_finish,
|
|
!(IPCB(skb)->flags & IPSKB_REROUTED));
|
|
}
|