mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 13:55:32 +00:00
![Herbert Xu](/assets/img/avatar_default.png)
As part of the work on asynchrnous cryptographic operations, we need to be able to resume from the spot where they occur. As such, it helps if we isolate them to one spot. This patch moves most of the remaining family-specific processing into the common output code. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
93 lines
2.1 KiB
C
93 lines
2.1 KiB
C
/*
|
|
* xfrm6_output.c - Common IPsec encapsulation code for IPv6.
|
|
* Copyright (C) 2002 USAGI/WIDE Project
|
|
* 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/icmpv6.h>
|
|
#include <linux/netfilter_ipv6.h>
|
|
#include <net/dst.h>
|
|
#include <net/ipv6.h>
|
|
#include <net/xfrm.h>
|
|
|
|
int xfrm6_find_1stfragopt(struct xfrm_state *x, struct sk_buff *skb,
|
|
u8 **prevhdr)
|
|
{
|
|
return ip6_find_1stfragopt(skb, prevhdr);
|
|
}
|
|
|
|
EXPORT_SYMBOL(xfrm6_find_1stfragopt);
|
|
|
|
static int xfrm6_tunnel_check_size(struct sk_buff *skb)
|
|
{
|
|
int mtu, ret = 0;
|
|
struct dst_entry *dst = skb->dst;
|
|
|
|
mtu = dst_mtu(dst);
|
|
if (mtu < IPV6_MIN_MTU)
|
|
mtu = IPV6_MIN_MTU;
|
|
|
|
if (skb->len > mtu) {
|
|
skb->dev = dst->dev;
|
|
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev);
|
|
ret = -EMSGSIZE;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int xfrm6_extract_output(struct xfrm_state *x, struct sk_buff *skb)
|
|
{
|
|
int err;
|
|
|
|
err = xfrm6_tunnel_check_size(skb);
|
|
if (err)
|
|
return err;
|
|
|
|
IP6CB(skb)->nhoff = offsetof(struct ipv6hdr, nexthdr);
|
|
return xfrm6_extract_header(skb);
|
|
}
|
|
|
|
int xfrm6_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(IP6CB(skb), 0, sizeof(*IP6CB(skb)));
|
|
#ifdef CONFIG_NETFILTER
|
|
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
|
|
#endif
|
|
|
|
skb->protocol = htons(ETH_P_IPV6);
|
|
|
|
return x->outer_mode->output2(x, skb);
|
|
}
|
|
EXPORT_SYMBOL(xfrm6_prepare_output);
|
|
|
|
static int xfrm6_output_finish(struct sk_buff *skb)
|
|
{
|
|
#ifdef CONFIG_NETFILTER
|
|
IP6CB(skb)->flags |= IP6SKB_XFRM_TRANSFORMED;
|
|
#endif
|
|
|
|
skb->protocol = htons(ETH_P_IPV6);
|
|
return xfrm_output(skb);
|
|
}
|
|
|
|
int xfrm6_output(struct sk_buff *skb)
|
|
{
|
|
return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb, NULL, skb->dst->dev,
|
|
xfrm6_output_finish);
|
|
}
|